395 lines
14 KiB
Perl
395 lines
14 KiB
Perl
# ==================================================================
|
|
# 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 "<pre>". Dumper($res)."</pre>";
|
|
|
|
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 "<pre>". Dumper($id,$result)."</pre>";
|
|
|
|
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;
|