discourse-legacysite-perl/site/slowtwitch.com/cgi-bin/articles/admin/Plugins/Auth_Facebook.pm
2024-06-17 21:49:12 +10:00

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;