Created
February 25, 2010 20:00
-
-
Save btrott/314967 to your computer and use it in GitHub Desktop.
This file contains 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
#!/usr/bin/perl -w | |
use strict; | |
use Plack::Builder; | |
use Plack::Request; | |
use Plack::Response; | |
use Text::MicroTemplate qw( render_mt ); | |
use WWW::TypePad; | |
# These should be set to the Consumer Key and Consumer Secret | |
# for your TypePad application. You can obtain these values from | |
# http://www.typepad.com/account/access/api_key. | |
our $ConsumerKey = ''; | |
our $ConsumerSecret = ''; | |
sub error { | |
my( $code, $html ) = @_; | |
return [ | |
$code, | |
[ 'Content-Type', 'text/html' ], | |
[ $html ], | |
]; | |
} | |
sub Plack::Request::uri_for { | |
my $req = shift; | |
my( $path ) = @_; | |
$path = '/' . $path unless $path =~ m{^/}; | |
return 'http://' . $req->env->{HTTP_HOST} . $path; | |
} | |
sub tp { | |
return WWW::TypePad->new( | |
consumer_key => $ConsumerKey, | |
consumer_secret => $ConsumerSecret, | |
); | |
} | |
my $home = sub { | |
my $req = Plack::Request->new( shift ); | |
my $tp = tp(); | |
# Do we have a logged-in user? If so, make an API request to pull down | |
# the user's profile info. Not that we're not using the access token | |
# and access token secret here, since this is a public API; but the | |
# access token and secret that we stored in the session could be used | |
# to make authenticated requests acting on behalf of the logged-in user. | |
my $session = $req->session; | |
my $obj; | |
if ( $session && $session->{user} ) { | |
$obj = $tp->users->get( $session->{user}{xid} ); | |
} | |
my $html = render_mt( <<'HTML', $obj ); | |
? my $user = $_[0]; | |
<html> | |
<head> | |
<title>TypePad mini-client</title> | |
<style type="text/css"> | |
body { font-family: Helvetica, Arial, Verdana, sans-serif; text-align: center; color: #333; } | |
h3 { margin-top: 250px; font-size: 48px; } | |
h5 { font-size: 12px; } | |
</style> | |
</head> | |
<body> | |
? if ( $user ) { | |
<h3>Welcome back, <a href="http://profile.typepad.com/<?= $user->{urlId} ?>"><?= $user->{displayName} ?></a>!</h3> | |
<h5><a href="/logout">(Sign out)</a></h5> | |
? } else { | |
<h3><a href="/login">Sign in</a></h3> | |
? } | |
</body> | |
</html> | |
HTML | |
my $res = Plack::Response->new( 200 ); | |
$res->content_type( 'text/html' ); | |
$res->body( $html ); | |
return $res->finalize; | |
}; | |
my $login = sub { | |
my $req = Plack::Request->new( shift ); | |
my $tp = tp(); | |
# After the user authorizes our application, he/she will be sent back | |
# to the callback URI ($login_cb below). | |
my $cb_uri = $req->uri_for( '/login-callback' ); | |
# Under the hood, get_authorization_url will request a request token, | |
# then construct a URI to send the user to to authorize our app. | |
my $uri = $tp->oauth->get_authorization_url( | |
callback => $cb_uri, | |
); | |
my $res = Plack::Response->new; | |
$res->redirect( $uri ); | |
# Store the token secret in the browser cookies for when this user | |
# returns from TypePad. | |
$res->cookies->{oauth_token_secret} = $tp->oauth->request_token_secret; | |
return $res->finalize; | |
}; | |
my $login_cb = sub { | |
my $req = Plack::Request->new( shift ); | |
my $tp = tp(); | |
# request_token is passed back to us via the query string | |
# as "oauth_token"... | |
my $token = $req->query_parameters->{oauth_token} | |
or return error( 400, 'No oauth_token' ); | |
# ... and the request_token_secret is stored in the browser cookie. | |
my $token_secret = $req->cookies->{oauth_token_secret} | |
or return error( 400, 'No oauth_token_secret cookie' ); | |
my $verifier = $req->query_parameters->{oauth_verifier} | |
or return error( 400, 'No oauth_verifier' ); | |
$tp->oauth->request_token( $token ); | |
$tp->oauth->request_token_secret( $token_secret ); | |
# Given the request token, token secret, and verifier that TypePad | |
# sent us, request an access token and secret that we can use for | |
# future authenticated calls on behalf of this user. | |
my( $access_token, $access_token_secret ) = | |
$tp->oauth->request_access_token( verifier => $verifier ); | |
$tp->access_token( $access_token ); | |
$tp->access_token_secret( $access_token_secret ); | |
# Now we've got an access token; make an authenticated request to figure | |
# out who we are, so we can associate the OAuth tokens to a local user. | |
my $obj = $tp->users->get( '@self' ); | |
return error( 500, 'Request for @self gave us empty result' ) | |
unless $obj; | |
# And store the user's xid, the access token, and access token | |
# secret in a session. In a real application, we'd store these | |
# in an actual datastore. | |
$req->session->{user} = { | |
xid => $obj->{urlId}, | |
token => $access_token, | |
token_secret => $access_token_secret, | |
}; | |
my $res = Plack::Response->new; | |
$res->redirect( $req->uri_for( '/' ) ); | |
# Remove the request token secret cookie that we created above. | |
$res->cookies->{oauth_token_secret} = { | |
value => '', | |
expires => time - 24 * 60 * 60, | |
}; | |
return $res->finalize; | |
}; | |
my $logout = sub { | |
my $req = Plack::Request->new( shift ); | |
# Kill the session. | |
$req->env->{'psgix.session'} = {}; | |
my $res = Plack::Response->new; | |
$res->redirect( $req->uri_for( '/' ) ); | |
return $res->finalize; | |
}; | |
builder { | |
# Sign session cookies using our API secret. You could use something | |
# else, if you want, but it's highly recommended to sign cookies with | |
# some secret. | |
enable 'Session::Cookie', secret => $ConsumerSecret; | |
mount '/' => $home; | |
mount '/login' => $login; | |
mount '/login-callback' => $login_cb; | |
mount '/logout' => $logout; | |
# Kill favicon requests. | |
mount '/favicon.ico' => sub { return error( 404, "not found" ) }; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment