Created
November 14, 2024 01:00
-
-
Save s1037989/0119f95d593b700bdef8a0e56e6e9e98 to your computer and use it in GitHub Desktop.
Flickr API OAuth and Upload
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package Mojolicious::Plugin::Flickr; | |
use Mojo::Base 'Mojolicious::Plugin', -signatures; | |
use Digest::SHA qw(hmac_sha1); | |
use Mojo::Collection qw(c); | |
use Mojo::JSON qw(j); | |
use Mojo::Parameters; | |
use Mojo::Util qw(b64_encode hmac_sha1_sum md5_sum url_escape); | |
has app => undef, weak => 1; | |
has oauth_params => sub ($self) { | |
return { | |
oauth_consumer_key => $self->app->flickr->consumer_key, | |
oauth_nonce => Mojo::Util::md5_sum(time . rand), | |
oauth_signature_method => 'HMAC-SHA1', | |
oauth_timestamp => time, | |
oauth_version => '1.0', | |
}; | |
}; | |
sub register { | |
my ($self, $app, $conf) = @_; | |
$self->app($app); | |
$conf ||= {}; | |
my $default = { | |
request_url => 'https://api.flickr.com/services/oauth/request_token', | |
auth_url => 'https://www.flickr.com/services/oauth/authorize', | |
callback_url => 'ceduler', # or oob | |
access_url => 'https://api.flickr.com/services/oauth/access_token', | |
rest_url => 'https://api.flickr.com/services/rest', | |
upload_url => 'https://up.flickr.com/services/upload/', | |
}; | |
die "flickr config is required" unless $app->config->{flickr}; | |
die "flickr.consumer_key config is required" unless $app->config->{flickr}{consumer_key}; | |
die "flickr.consumer_secret config is required" unless $app->config->{flickr}{consumer_secret}; | |
for my $key (c(keys $app->config->{flickr}->%*, keys(%$conf), keys(%$default))->uniq->grep(sub{$_})->@*) { | |
$app->helper("flickr.$key" => sub ($c) { | |
my $value = $app->config->{flickr}{$key} || $conf->{$key} || $default->{$key}; | |
return $value && $key =~ /_url$/ ? $c->url_for($value)->to_abs : $value; | |
}); | |
} | |
$app->ua->on(prepare => sub ($ua, $tx) { | |
my $url = $tx->req->url->clone->query(Mojo::Parameters->new)->to_abs->to_string; | |
$app->log->trace(sprintf 'prepare url: %s', $tx->req->url->to_abs); | |
$app->log->trace(sprintf 'base url: %s', $url); | |
$app->log->trace(sprintf 'query: %s', $tx->req->url->query->to_string); | |
if ($url eq $app->flickr->request_url->to_abs) { | |
$app->log->trace('------ START REQUEST TOKEN'); | |
$self->_sign_request($tx); | |
$app->log->trace('------ END REQUEST TOKEN'); | |
} | |
elsif ($url eq $app->flickr->access_url->to_abs) { | |
$app->log->trace('------ START ACCESS TOKEN'); | |
$self->_sign_access($tx); | |
$app->log->trace('------ END ACCESS TOKEN'); | |
} | |
elsif ($url eq $app->flickr->rest_url->to_abs) { | |
$app->log->trace('------ START REST'); | |
$self->_sign_rest($tx); | |
$app->log->trace('------ END REST'); | |
} | |
elsif ($url eq $app->flickr->upload_url->to_abs) { | |
$app->log->trace('------ START UPLOAD'); | |
$self->_sign_upload($tx); | |
$app->log->trace('------ END UPLOAD'); | |
} | |
}); | |
} | |
sub _extract_keys ($self, $tx) { | |
$self->app->log->trace('%s', $tx->req->headers->header('X-Keys')); | |
my $keys = j($tx->req->headers->header('X-Keys')); | |
$tx->req->headers->remove('X-Keys'); | |
return $keys; | |
} | |
sub _join { join '&', map { url_escape $_ } @_ } | |
sub _sign ($self, $tx, $keys, $param_str) { | |
my $base_str = _join($tx->req->method, $tx->req->url->clone->query(Mojo::Parameters->new)->to_string, $param_str); | |
my $signing_key = _join($self->app->flickr->consumer_secret, $keys->{oauth_token_secret}); | |
my $signature = b64_encode(hmac_sha1($base_str, $signing_key), ''); | |
$self->app->log->trace(sprintf 'param_str: %s', $param_str); | |
$self->app->log->trace(sprintf 'base_str: %s', $base_str); | |
$self->app->log->trace(sprintf 'signing_key: %s', $signing_key); | |
$self->app->log->trace(sprintf 'signature: %s', $signature); | |
$self->app->log->trace(sprintf 'headers: %s', $tx->req->headers->to_string); | |
$self->app->log->trace(sprintf 'oauth url: %s', $tx->req->url->to_abs); | |
return $signature; | |
} | |
sub _sign_request ($self, $tx) { | |
my $keys = {oauth_token_secret => ''}; | |
my $url = $tx->req->url; | |
$url->query($self->oauth_params); | |
my $params = $url->query->to_hash; | |
my $param_str = join '&', map { sprintf '%s=%s', $_, url_escape $params->{$_} } sort keys %$params; | |
$url->query({oauth_signature => $self->_sign($tx, $keys, $param_str)}); | |
} | |
sub _sign_access ($self, $tx) { | |
my $keys = {oauth_token_secret => $self->app->home->child('keys')->child($tx->req->param('oauth_token'))->slurp}; | |
my $url = $tx->req->url; | |
$url->query($self->oauth_params); | |
my $params = $url->query->to_hash; | |
my $param_str = join '&', map { sprintf '%s=%s', $_, url_escape $params->{$_} } sort keys %$params; | |
$url->query({oauth_signature => $self->_sign($tx, $keys, $param_str)}); | |
} | |
sub _sign_rest ($self, $tx) { | |
my $keys = $self->_extract_keys($tx); | |
my $url = $tx->req->url; | |
$url->query($self->oauth_params); | |
$url->query({oauth_token => $keys->{oauth_token}}); | |
my $params = $url->query->to_hash; | |
my $param_str = join '&', map { sprintf '%s=%s', $_, url_escape $params->{$_} } sort keys %$params; | |
$url->query({oauth_signature => $self->_sign($tx, $keys, $param_str)}); | |
} | |
sub _sign_upload ($self, $tx) { | |
my $keys = $self->_extract_keys($tx); | |
my $url = $tx->req->url; | |
my $params = $self->oauth_params; | |
$params->{api_key} = $params->{oauth_consumer_key}; | |
$params->{oauth_token} = $keys->{oauth_token}; | |
my $param_str = join '&', map { sprintf '%s=%s', $_, url_escape $params->{$_} } grep { !/^(photo)$/ } sort keys %$params; | |
$params->{oauth_signature} = $self->_sign($tx, $keys, $param_str); | |
$tx->req->headers->authorization('OAuth ' . join ', ', map { sprintf '%s="%s"', $_, $params->{$_} } sort keys %$params); | |
} | |
1; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment