# ================================================================== # Plugins::Auth_Facebook - Auto Generated Program Module # # Plugins::Auth_Facebook # Author : Gossamer Threads Inc. (Virginia Lo) # Version : 1.1 # Updated : Wed Feb 2 10:34:55 2011 # # ================================================================== # package Plugins::Auth_Facebook; # ================================================================== use strict; use GT::Base; use GT::Plugins qw/STOP CONTINUE/; use Links qw/:objects/; use vars qw/$TAINTED $GRAPHURL $CALLBACK $AUTHURL $FBMAPPING/; use GT::WWW; use GT::JSON; use Data::Dumper; use Links::Plugins; use open qw(:std :utf8); use LWP::Simple; use JSON; use URI; use utf8; # Inherit from base class for debug and error methods @Plugins::Auth_Facebook::ISA = qw(GT::Base); # Your code begins here. { local $^W = 0; $TAINTED = substr("$0$^X", 0, 0); } $GRAPHURL = "https://graph.facebook.com"; $AUTHURL = $GRAPHURL . '/oauth/access_token'; $FBMAPPING = { first_name => 'prof_first_name', last_name => 'prof_last_name', email => 'comm_email', }; # PLUGIN HOOKS # =================================================================== sub user_auth { # ------------------------------------------------------------------- # ether facebook postback or user call it. # my $cfg = Links::Plugins::get_plugin_user_cfg('Auth_Facebook'); $CALLBACK = $cfg->{fb_postback_url}; my $redirect = $IN->param('url'); my $ajax = $IN->param('ajax'); my $cuser = $USER; # Check to see if we have the facebook cookie already. $Links::fbcookie ||= get_facebook_cookie(); my $code = $IN->param('code'); my $connect = $IN->param('connect'); if ($code) { # --------------------------------------------------------------------- # User has granted permission to the app to access their information. # Post a request to facebook to verify the code which can be exchanged for an oauth access token # --------------------------------------------------------------------- # If the user authorizes your application, we redirect the user back # to the redirect URI you specified with a verification string in the # argument code, which can be exchanged for an oauth access token. # --------------------------------------------------------------------- if ($connect) { $CALLBACK .= "&connect=1"; } my $linkid = $IN->param('linkid'); if ($linkid) { $CALLBACK .= "$linkid/"; } my $authurl = $AUTHURL . "?client_id=" . $cfg->{fb_appid} . "&redirect_uri=" . GT::CGI::escape($CALLBACK) . "&client_secret=" . $cfg->{fb_secret_key} . "&code=" . $code; my $res = GT::WWW->post($authurl); #print $IN->header; #print "
".  Dumper($res)."
"; if ($res->{content} =~ /access_token=(.+)$/) { # we got the access token my $access_token = $1; $access_token =~ s/\&.+$//g; # Fix it by removing the &epxire=[timestamp] #print $access_token . "**"; my $id = $linkid; use Plugins::SocialMedia; my $result = Plugins::SocialMedia::post_facebook($access_token, $id); #my $result = {}; #Plugins::SocialMedia::post_facebook($access_token, $id); #print "
".  Dumper($id,$result)."
"; if ($result) { if ($result->{id}) { $DB->table('Links')->update({ facebook_published => $result->{id} }, { ID => $linkid }); } elsif ($result->{error}) { $DB->table('Links')->update({ facebook_published_message => $result->{error}->{message} }, { ID => $linkid }); } $IN->param('t','dev'); #FIXME require Plugins::SocialMedia; my $link = Plugins::SocialMedia::format_link($linkid); print $IN->header; print Links::user_page('add_success_publish.html', { success => '1', built => 1, %$link }); return; } else { $IN->param('t','dev'); #FIXME require Plugins::SocialMedia; my $link = Plugins::SocialMedia::format_link($id); print $IN->header; print Links::user_page('add_success_publish.html', { success => '1', built => 1, %$link }); return; } =tag # get the user information my $userinfo = request_facebook_api('me','email', $access_token); # check to seee if the user already in community my $user = user_by_facebook_id($userinfo->{id}); # --------------------------------------------------------------------- # Now then login user with their facebook account # --------------------------------------------------------------------- if ($user) { my $cookies = []; my $remember = 1; my $username = $user->{comm_username}; # create community session. $user->{session} = comm_create_session( comm_id => $user->{comm_id}, remember => $remember, ip => $ENV{REMOTE_ADDR} ); # Get session cookies, and send user to home page or to redirection. my $session_cookies = Links::session_cookies($user, $remember ? $CFG->{session_remember_expiry} : undef); push @$cookies, @$session_cookies; if ($redirect) { comm_debug("user |$username| logged in. Redirecting to |$redirect|") if ($CFG->{debug}); print $IN->header( -url => $redirect, -cookie => $cookies ); return; } else { $user->{redirect} = $IN->cookie('fb_redirect'); comm_debug("user |$username| logged in.") if ($CFG->{debug}); $user->{session_cookie_name_user} = $user->{comm_username}; $user->{action} = 'login'; print $IN->header( -cookie => $cookies ); Links::user_page('user_logged_in.html', { %$user }); return; } } else { # --------------------------------------------------------------------- # Show signup form if they are not in Community but already authorize our app to access their account # --------------------------------------------------------------------- # Write the facebook cookies here so that we can access them again after the user # provides us with username. I don't see where else this is being done. # --------------------------------------------------------------------- my $cookies = []; my $remember = 1; my $facebook_cookies = facebook_cookies($userinfo, $remember ? $CFG->{session_remember_expiry} : undef); push @$cookies, @$facebook_cookies; if ($connect) { if (defined $IN->cookie('fb_uid')) { $userinfo->{facebook_userid} = $IN->cookie('fb_uid'); } print $IN->header( -cookie => $cookies ); Links::user_page('user_connect.html', { fb_user => $userinfo, user => $cuser }); return; } print $IN->header( -cookie => $cookies ); my @questions; foreach my $question (@{$CFG->{signup_questions}}) { push @questions, { question => $question }; } my $res = { comm_question_loop => \@questions, fb_user => $userinfo, fb_signup => 1, }; $res->{fancybox} = $IN->param('fancybox') ? 1 : 0; $res->{iframe} = 1; $res->{debuginfo} = { cookies => \@$cookies, %$userinfo }; foreach (keys %$userinfo) { $res->{querystr} .= "&" if ($res->{querystr}); $res->{querystr} .= $_ . "=" . $userinfo->{$_}; } if ($userinfo->{birthday}) { ($res->{prof_mon}, $res->{prof_day}, $res->{prof_year}) = split ('/', $userinfo->{birthday}); $res->{prof_month} =~ s/^0//g; $res->{prof_day} =~ s/^0//g; } Links::user_page('user_signup_fb_popup.html', $res); return; } =cut } else { print $IN->header; } } elsif ($IN->param('error')) { print $IN->header; Links::user_page('user_signup_fb_error.html', { error => $IN->param('error') }); return; } else { # redirect user to facebook and ask for email, offline access, read access # display=popup mean it's a popup format. my $cookie = [ $IN->cookie( -name => "fb_redirect", -value => $redirect ? $redirect : '', -expires => undef, -path => $CFG->{session_cookie_path} ) ]; if ($IN->param('connect')) { $CALLBACK .= "&connect=1"; } my $linkid = $IN->param('linkid'); if ($linkid) { $CALLBACK .= "$linkid/"; my $tags = $IN->param('twitter_hash_tags'); my $newtags; if ($tags) { $tags =~ s/\s+//g; my @tags = split(',',$tags); for (@tags) { $newtags .= ' #' . $_; } } $DB->table('Links')->update({ facebook_hashtags => $newtags }, { ID => $linkid }) if ($newtags); } my $redirurl = 'https://graph.facebook.com/oauth/authorize?client_id=' . $cfg->{fb_appid} . '&redirect_uri=' . GT::CGI::escape($CALLBACK) . '&scope=email,read_stream,publish_stream,manage_pages'; if (1) { # HAS to have display=popup to show "Log in to Facebook" button $redirurl .= "&display=popup"; } print $IN->header( -url => $redirurl, -cookie => $cookie ); return; } } sub request_facebook_api { # ------------------------------------------------------------------- # generate facebook api and make a request # the request results are in json format # my ($uid, $type, $token, $publish, $args) = @_; if (!$token) { $Links::fbcookie ||= get_facebook_cookie(); } $type ||= "feed"; require GT::WWW; my $content; my $www = new GT::WWW; # Note: apparently we need to unescape the token, not escape it. # perhaps it's a difference between $token and access_token? # http://drupal.org/node/905164 post #7 as of 9/29/2010 my $host = $GRAPHURL; $host =~ s/^(https)?:\/\///g; $www->protocol($1); $www->host($host); if ($publish) { $www->path("/$uid/feed"); $www->parameters(access_token => GT::CGI::unescape($token || $Links::fbcookie->{access_token})); $args ||= $IN->get_hash(); #use Data::Dumper; print Dumper($args); for (qw/message picture name caption description link/) { $www->parameters($_ => GT::CGI::html_escape($args->{$_}), 1) if ($args->{$_} !~ /^\s*$/); } $content = $www->post(); } else { my $requestpath = "/" . $uid; $requestpath .= "/" . $type if ($uid ne 'me'); $www->path($requestpath); $www->parameters(access_token => GT::CGI::unescape($token || $Links::fbcookie->{access_token})); $args ||= $IN->get_hash(); if ($uid ne 'me') { for (keys %$args) { next if ($_ eq 'arg'); $www->parameters($_ => GT::CGI::html_escape($args->{$_}), 1) if ($args->{$_} !~ /^\s*$/); } } $content = $www->get(); } return unless ($content); my $data = eval { $content }; return unless ($data and $data->{content}); my $res = from_json($data->{content}); return $res; } sub get_facebook_cookie { # ------------------------------------------------------------------- # return facebook cookie in hash if exists # my $cfg = Links::Plugins::get_plugin_user_cfg('Auth_Facebook'); my ($app_id, $application_secret) = ($cfg->{fb_appid}, $cfg->{fb_secret_key}); my $cookiename = 'fbs_' . $cfg->{fb_appid}; my $cookies = {}; if (defined $ENV{HTTP_COOKIE}) { for (split /;\s*/, $ENV{HTTP_COOKIE}) { /(.*)="?(.*)"?/ or next; my ($key, $val) = (GT::CGI::unescape($1 . $TAINTED), GT::CGI::unescape($2 . $TAINTED)); if ($_ =~ /(.*)="([^"]+)+"/) { ($key, $val) = (GT::CGI::unescape($1 . $TAINTED), GT::CGI::unescape($2 . $TAINTED)); } $val = [split '&', $val]; foreach (@$val) { my ($k, $v) = split /=/, $_; $cookies->{$key}->{$k} = $v; } } } my $args = $cookies->{$cookiename}; my $payload; foreach my $key (sort keys %$args) { if ($key ne 'sig') { $payload .= $key . '=' . $args->{$key}; } } require GT::MD5; my $md5 = GT::MD5::md5_hex($payload . $application_secret); return unless ($md5 eq $args->{'sig'}); return $args; } sub facebook_cookies { # ------------------------------------------------------------------- # return facebook cookies, and put it into the cookies list # in case we need it later. # my ($facebookinfo, $expiry) = @_; $facebookinfo || return; my $cookies = [ $IN->cookie( -name => "fb_uid", -value => $facebookinfo ? $facebookinfo->{id} : '', -expires => $expiry, -path => $CFG->{session_cookie_path} ) ]; if ($CFG->{session_cookie_domain}) { push @$cookies, $IN->cookie( -name => "fb_uid", -value => $facebookinfo ? $facebookinfo->{id} : '', -expires => $expiry, -path => $CFG->{session_cookie_path}, -domain => $CFG->{session_cookie_domain} ); } return $cookies; } sub user_by_facebook_id { # ------------------------------------------------------------------- # pass in facebook profile id and return the community user # associated with it if exists. # my $uid = shift || return; my $db = $DB->table('Users'); return; my $sth = $db->select( { facebook_userid => $uid }); if ($sth->rows) { my $user = $sth->fetchrow_hashref; return $user; } return; } # Always end with a 1. 1;