]> git.mxchange.org Git - quix0rs-gnu-social.git/commitdiff
Facebook bridge back in business with new JS-SDK and OAuth 2.0 flow.
authorZach Copley <zach@status.net>
Tue, 27 Sep 2011 04:09:47 +0000 (04:09 +0000)
committerZach Copley <zach@status.net>
Tue, 27 Sep 2011 04:09:47 +0000 (04:09 +0000)
Might be better to rewrite the login mechanism to use server side flow
now that Facebook provides it.

classes/Foreign_user.php
plugins/FacebookBridge/FacebookBridgePlugin.php
plugins/FacebookBridge/actions/facebookdeauthorize.php
plugins/FacebookBridge/actions/facebookfinishlogin.php
plugins/FacebookBridge/actions/facebooklogin.php
plugins/FacebookBridge/lib/facebookclient.php

index 67d8651fa97537f0bde2061bc188775a911d9eda..4a41e07f4d87d796d750140a29ef981a8a9642cf 100644 (file)
@@ -44,20 +44,18 @@ class Foreign_user extends Managed_DataObject
         );
     }
 
-    // XXX:  This only returns a 1->1 single obj mapping.  Change?  Or make
-    // a getForeignUsers() that returns more than one? --Zach
     static function getForeignUser($id, $service) {
+
         $fuser = new Foreign_user();
-        $fuser->whereAdd("service = $service");
-        $fuser->whereAdd("id = $id");
+
+        $fuser->id      = $id;
+        $fuser->service = $service;
+
         $fuser->limit(1);
 
-        if ($fuser->find()) {
-            $fuser->fetch();
-            return $fuser;
-        }
+        $result = $fuser->find(true);
 
-        return null;
+        return empty($result) ? null : $fuser;
     }
 
     static function getByNickname($nickname, $service)
index 9d83c9f474f88e1653d87de5c696ac540f382c08..bf16da337dc7137852b1c17075cfd6e11e0edc60 100644 (file)
@@ -103,8 +103,6 @@ class FacebookBridgePlugin extends Plugin
     {
         $dir = dirname(__FILE__);
 
-        //common_debug("class = " . $cls);
-
         switch ($cls)
         {
         case 'Facebook': // Facebook PHP SDK
@@ -352,6 +350,13 @@ class FacebookBridgePlugin extends Plugin
             $action->script('https://connect.facebook.net/en_US/all.js');
 
             $script = <<<ENDOFSCRIPT
+function setCookie(name, value) {
+    var date = new Date();
+    date.setTime(date.getTime() + (5 * 60 * 1000)); // 5 mins
+    var expires = "; expires=" + date.toGMTString();
+    document.cookie = name + "=" + value + expires + "; path=/";
+}
+
 FB.init({appId: %1\$s, status: true, cookie: true, xfbml: true, oauth: true});
 
 $('#facebook_button').bind('click', function(event) {
@@ -360,6 +365,8 @@ $('#facebook_button').bind('click', function(event) {
 
     FB.login(function(response) {
         if (response.authResponse) {
+            // put the access token in a cookie for the next step
+            setCookie('fb_access_token', response.authResponse.accessToken);
             window.location.href = '%2\$s';
         } else {
             // NOP (user cancelled login)
@@ -383,24 +390,30 @@ ENDOFSCRIPT;
      *
      * @param Action action the current action
      */
-    function onEndLogout($action)
+    function onStartLogout($action)
     {
         if ($this->hasApplication()) {
-            //$session = $this->facebook->getSession();
-            $fbuser  = null;
-            $fbuid   = null;
 
-                try {
-                    $fbuid  = $this->facebook->getUser();
-                    $fbuser = $this->facebook->api('/me');
-                 } catch (FacebookApiException $e) {
-                     common_log(LOG_ERROR, $e, __FILE__);
-                 }
+            $cur = common_current_user();
+            $flink = Foreign_link::getByUserID($cur->id, FACEBOOK_SERVICE);
+
+            if (!empty($flink)) {
+
+                $this->facebook->setAccessToken($flink->credentials);
 
-            if (!empty($fbuser)) {
+                if (common_config('singleuser', 'enabled')) {
+                    $user = User::singleUser();
+
+                    $destination = common_local_url(
+                        'showstream',
+                        array('nickname' => $user->nickname)
+                    );
+                } else {
+                    $destination = common_local_url('public');
+                }
 
                 $logoutUrl = $this->facebook->getLogoutUrl(
-                    array('next' => common_local_url('public'))
+                    array('next' => $destination)
                 );
 
                 common_log(
@@ -411,9 +424,14 @@ ENDOFSCRIPT;
                     ),
                     __FILE__
                 );
-                common_debug("LOGOUT URL = $logoutUrl");
+
+                $action->logout();
+
                 common_redirect($logoutUrl, 303);
+                return false; // probably never get here, but hey
             }
+
+            return true;
         }
     }
 
index 1a83c3a003c1baad4a8839a44fb5760d0be1f8ae..443b768f5c83215db241e3ed132c7000abfa26cd 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 /**
  * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2010, StatusNet, Inc.
+ * Copyright (C) 2010-2011, StatusNet, Inc.
  *
  * An action that handles deauthorize callbacks from Facebook
  *
@@ -23,7 +23,7 @@
  * @category  Plugin
  * @package   StatusNet
  * @author    Zach Copley <zach@status.net>
- * @copyright 2010 StatusNet, Inc.
+ * @copyright 2010-2011 StatusNet, Inc.
  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
  * @link      http://status.net/
  */
index d58944e83df53cb66feaa008d623447e88a7ed77..260761e862d07f3e24686766160683dff58af5ff 100644 (file)
@@ -42,37 +42,24 @@ class FacebookfinishloginAction extends Action
 
         // Check cookie for a valid access_token
 
-        $cookie = $this->get_facebook_cookie(
-            common_config('facebook', 'appid'),
-            common_config('facebook', 'secret')
-        );
-
-        $this->accessToken = $cookie['access_token'];
+        if (isset($_COOKIE['fb_access_token'])) {
+            $this->accessToken = $_COOKIE['fb_access_token'];
+            if (empty($this->accessToken)) {
+                $this->clientError(_m("Unable to authenticate you with Facebook."));
+                return false;
+            }
+        }
 
-        common_debug("cookie = " . var_export($cookie, true));
-
-        $this->fbuser = json_decode(
-            file_get_contents(
-                'https://graph.facebook.com/me?access_token='
-                . $this->accessToken
-            )
-        );
+        $graphUrl = 'https://graph.facebook.com/me?access_token=' . urlencode($this->accessToken);
+        $this->fbuser = json_decode(file_get_contents($graphUrl));
 
         if (!empty($this->fbuser)) {
-
             $this->fbuid  = $this->fbuser->id;
-            common_debug("fbuser = " . var_export($this->fbuser, true));
-            common_debug("fbuid = " . $this->fbuid);
-
             // OKAY, all is well... proceed to register
-
-            common_debug("Found a valid Facebook user.", __FILE__);
-
             return true;
-
         } else {
 
-            // This shouldn't happen in the regular course of things
+            // log badness
 
             list($proxy, $ip) = common_client_ip();
 
@@ -95,27 +82,6 @@ class FacebookfinishloginAction extends Action
         return false;
     }
 
-    function get_facebook_cookie($app_id, $app_secret) {
-        $args = array();
-
-        parse_str(trim($_COOKIE['fbs_' . $app_id], '\\"'), $args);
-
-        ksort($args);
-        $payload = '';
-
-        foreach ($args as $key => $value) {
-            if ($key != 'sig') {
-               $payload .= $key . '=' . $value;
-            }
-        }
-
-        if (md5($payload . $app_secret) != $args['sig']) {
-            return null;
-        }
-
-        return $args;
-    }
-
     function handle($args)
     {
         parent::handle($args);
@@ -148,14 +114,6 @@ class FacebookfinishloginAction extends Action
 
             // User already has a linked Facebook account and shouldn't be here!
 
-            common_debug(
-                sprintf(
-                    'There\'s already a local user %d linked with Facebook user %s.',
-                    $flink->user_id,
-                    $this->fbuid
-                )
-            );
-
             $this->clientError(
                 // TRANS: Client error displayed when trying to connect to a Facebook account that is already linked
                 // TRANS: in the same StatusNet site.
@@ -172,14 +130,6 @@ class FacebookfinishloginAction extends Action
 
             // There's already a local user linked to this Facebook account.
 
-            common_debug(
-                sprintf(
-                    'There\'s already a local user %d linked with Facebook user %s.',
-                    $cur->id,
-                    $this->fbuid
-                )
-            );
-
             $this->clientError(
                 // TRANS: Client error displayed when trying to connect to a Facebook account that is already linked
                 // TRANS: in the same StatusNet site.
@@ -194,6 +144,7 @@ class FacebookfinishloginAction extends Action
     {
         $token = $this->trimmed('token');
 
+        // CSRF protection
         if (!$token || $token != common_session_token()) {
             $this->showForm(
                 // TRANS: Client error displayed when the session token does not match or is not given.
@@ -481,64 +432,58 @@ class FacebookfinishloginAction extends Action
      */
     function setAvatar($user)
     {
-        $picUrl = sprintf(
-            'http://graph.facebook.com/%s/picture?type=large',
-            $this->fbuid
-        );
-
-        // fetch the picture from Facebook
-        $client = new HTTPClient();
+         try {
+            $picUrl = sprintf(
+                'http://graph.facebook.com/%d/picture?type=large',
+                $this->fbuser->id
+            );
 
-        // fetch the actual picture
-        $response = $client->get($picUrl);
+            // fetch the picture from Facebook
+            $client = new HTTPClient();
 
-        if ($response->isOk()) {
+            // fetch the actual picture
+            $response = $client->get($picUrl);
 
-            $finalUrl = $client->getUrl();
+            if ($response->isOk()) {
 
-            // Make sure the filename is unique becuase it's possible for a user
-            // to deauthorize our app, and then come back in as a new user but
-            // have the same Facebook picture (avatar URLs have a unique index
-            // and their URLs are based on the filenames).
-            $filename = 'facebook-' . common_good_rand(4) . '-'
-                . substr(strrchr($finalUrl, '/'), 1);
+                // seems to always be jpeg, but not sure
+                $tmpname = "facebook-avatar-tmp-" . common_good_rand(4);
 
-            $ok = file_put_contents(
-                Avatar::path($filename),
-                $response->getBody()
-            );
-
-            if (!$ok) {
-                common_log(
-                    LOG_WARNING,
-                    sprintf(
-                        'Couldn\'t save Facebook avatar %s',
-                        $tmp
-                    ),
-                    __FILE__
+                $ok = file_put_contents(
+                    Avatar::path($tmpname),
+                    $response->getBody()
                 );
 
-            } else {
-
-                // save it as an avatar
-                $profile = $user->getProfile();
-
-                if ($profile->setOriginal($filename)) {
-                    common_log(
-                        LOG_INFO,
-                        sprintf(
-                            'Saved avatar for %s (%d) from Facebook picture for '
-                                . '%s (fbuid %d), filename = %s',
-                             $user->nickname,
-                             $user->id,
-                             $this->fbuser->name,
-                             $this->fbuid,
-                             $filename
-                        ),
-                        __FILE__
-                    );
+                if (!$ok) {
+                    common_log(LOG_WARNING, 'Couldn\'t save tmp Facebook avatar: ' . $tmpname, __FILE__);
+                } else {
+                    // save it as an avatar
+                    $profile   = $user->getProfile();
+
+                    if ($profile->setOriginal($tmpname)) {
+                        common_log(
+                            LOG_INFO,
+                            sprintf(
+                                'Saved avatar for %s (%d) from Facebook picture for '
+                                    . '%s (fbuid %d), filename = %s',
+                                 $user->nickname,
+                                 $user->id,
+                                 $this->fbuser->name,
+                                 $this->fbuid,
+                                 $filename
+                             ),
+                             __FILE__
+                        );
+
+                        // clean up
+                        @unlink(Avatar::path($tmpname));
+                    }
+
                 }
             }
+        } catch (Exception $e) {
+            common_log(LOG_WARNING, 'Couldn\'t save Facebook avatar: ' . $e->getMessage(), __FILE__);
+            // error isn't fatal, continue
         }
     }
 
@@ -555,22 +500,14 @@ class FacebookfinishloginAction extends Action
 
         $user = User::staticGet('nickname', $nickname);
 
-        if (!empty($user)) {
-            common_debug(
-                sprintf(
-                    'Found a legit user to connect to Facebook: %s (%d)',
-                    $user->nickname,
-                    $user->id
-                ),
-                __FILE__
-            );
-        }
-
         $this->tryLinkUser($user);
 
         common_set_user($user);
         common_real_login(true);
 
+        // clear out the stupid cookie
+        setcookie('fb_access_token', '', time() - 3600); // one hour ago
+
         $this->goHome($user->nickname);
     }
 
@@ -578,6 +515,9 @@ class FacebookfinishloginAction extends Action
     {
         $user = common_current_user();
         $this->tryLinkUser($user);
+
+        // clear out the stupid cookie
+        setcookie('fb_access_token', '', time() - 3600); // one hour ago
         common_redirect(common_local_url('facebookfinishlogin'), 303);
     }
 
@@ -590,29 +530,10 @@ class FacebookfinishloginAction extends Action
             $this->serverError(_m('Error connecting user to Facebook.'));
             return;
         }
-
-        common_debug(
-            sprintf(
-                'Connected Facebook user %s (fbuid %d) to local user %s (%d)',
-                $this->fbuser->name,
-                $this->fbuid,
-                $user->nickname,
-                $user->id
-            ),
-            __FILE__
-        );
     }
 
     function tryLogin()
     {
-        common_debug(
-            sprintf(
-                'Trying login for Facebook user %s',
-                $this->fbuid
-            ),
-            __FILE__
-        );
-
         $flink = Foreign_link::getByForeignID($this->fbuid, FACEBOOK_SERVICE);
 
         if (!empty($flink)) {
@@ -633,19 +554,14 @@ class FacebookfinishloginAction extends Action
 
                 common_set_user($user);
                 common_real_login(true);
+
+                // clear out the stupid cookie
+                setcookie('fb_access_token', '', time() - 3600); // one hour ago
+
                 $this->goHome($user->nickname);
             }
 
         } else {
-
-            common_debug(
-                sprintf(
-                    'No flink found for fbuid: %s - new user',
-                    $this->fbuid
-                ),
-                __FILE__
-            );
-
             $this->showForm(null, $this->bestNewNickname());
         }
     }
@@ -668,14 +584,12 @@ class FacebookfinishloginAction extends Action
     function flinkUser($user_id, $fbuid)
     {
         $flink = new Foreign_link();
-        $flink->user_id = $user_id;
-        $flink->foreign_id = $fbuid;
-        $flink->service = FACEBOOK_SERVICE;
 
-        // Pull the access token from the Facebook cookies
+        $flink->user_id     = $user_id;
+        $flink->foreign_id  = $fbuid;
+        $flink->service     = FACEBOOK_SERVICE;
         $flink->credentials = $this->accessToken;
-
-        $flink->created = common_sql_now();
+        $flink->created     = common_sql_now();
 
         $flink_id = $flink->insert();
 
index afb30a2b1f969dba6c79f25317569d316485feab..f30822b63f536dfd78fbb89304d8c4495774033f 100644 (file)
@@ -23,7 +23,7 @@
  * @category  Plugin
  * @package   StatusNet
  * @author    Zach Copley <zach@status.net>
- * @copyright 2010 StatusNet, Inc.
+ * @copyright 2010-2011 StatusNet, Inc.
  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
  * @link      http://status.net/
  */
@@ -98,16 +98,6 @@ class FacebookloginAction extends Action
 
         $this->elementEnd('a');
 
-        /*
-        $this->element('div', array('id' => 'fb-root'));
-        $this->script(
-            sprintf(
-                'http://connect.facebook.net/en_US/all.js#appId=%s&xfbml=1',
-                common_config('facebook', 'appid')
-            )
-        );
-        $this->element('fb:facepile', array('max-rows' => '2', 'width' =>'300'));
-        */
         $this->elementEnd('fieldset');
     }
 
index 768950ffa25817d5adf004d26abd327a813d427f..00b313b6a4d9320d1c4891300a0fe08430c7eec7 100644 (file)
@@ -23,7 +23,7 @@
  * @package   StatusNet
  * @author    Craig Andrews <candrews@integralblue.com>
  * @author    Zach Copley <zach@status.net>
- * @copyright 2009-2010 StatusNet, Inc.
+ * @copyright 2009-2011 StatusNet, Inc.
  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
  * @link      http://status.net/
  */
@@ -927,8 +927,8 @@ class Facebookclient
                     LOG_INFO,
                     sprintf(
                         'Removed old Facebook user: %s, fbuid %d',
-                        $fbuid['name'],
-                        $fbuid['id']
+                        $fbuid->name,
+                        $fbuid->id
                     ),
                     __FILE__
                 );
@@ -938,7 +938,7 @@ class Facebookclient
         $fuser = new Foreign_user();
 
         $fuser->nickname = $fbuser->username;
-        $fuser->uri      = $fbuser->url;
+        $fuser->uri      = $fbuser->link;
         $fuser->id       = $fbuser->id;
         $fuser->service  = FACEBOOK_SERVICE;
         $fuser->created  = common_sql_now();