X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=plugins%2FFacebookBridge%2Factions%2Ffacebookfinishlogin.php;h=4a9e09b53dfe1c27fe1f9a0ce2b7987c8d0e8a98;hb=d6b28c64830f632bb2f4b6f3c9369b9e56ad217a;hp=7b2f27474173c02153fb28b437de1a5e3b1da80e;hpb=c0bb1a57984266024e8e5a968c0f3a3b54befff6;p=quix0rs-gnu-social.git diff --git a/plugins/FacebookBridge/actions/facebookfinishlogin.php b/plugins/FacebookBridge/actions/facebookfinishlogin.php index 7b2f274741..4a9e09b53d 100644 --- a/plugins/FacebookBridge/actions/facebookfinishlogin.php +++ b/plugins/FacebookBridge/actions/facebookfinishlogin.php @@ -22,7 +22,7 @@ * @category Plugin * @package StatusNet * @author Zach Copley - * @copyright 2010 StatusNet, Inc. + * @copyright 2010-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/ */ @@ -33,44 +33,28 @@ if (!defined('STATUSNET')) { class FacebookfinishloginAction extends Action { - private $facebook = null; // Facebook client - private $fbuid = null; // Facebook user ID - private $fbuser = null; // Facebook user object (JSON) - - function prepare($args) { + private $fbuid = null; // Facebook user ID + private $fbuser = null; // Facebook user object (JSON) + private $accessToken = null; // Access token provided by Facebook JS API + function prepare(array $args=array()) { parent::prepare($args); - $this->facebook = new Facebook( - array( - 'appId' => common_config('facebook', 'appid'), - 'secret' => common_config('facebook', 'secret'), - 'cookie' => true, - ) - ); - - // Check for a Facebook user session - - $session = $this->facebook->getSession(); - $me = null; + // Check cookie for a valid access_token - if ($session) { - try { - $this->fbuid = $this->facebook->getUser(); - $this->fbuser = $this->facebook->api('/me'); - } catch (FacebookApiException $e) { - common_log(LOG_ERROR, $e, __FILE__); - } + if (isset($_COOKIE['fb_access_token'])) { + $this->accessToken = $_COOKIE['fb_access_token']; } - if (!empty($this->fbuser)) { - - // OKAY, all is well... proceed to register + if (empty($this->accessToken)) { + $this->clientError(_m("Unable to authenticate you with Facebook.")); + } - common_debug("Found a valid Facebook user.", __FILE__); - } else { + $graphUrl = 'https://graph.facebook.com/me?access_token=' . urlencode($this->accessToken); + $this->fbuser = json_decode(file_get_contents($graphUrl)); - // This shouldn't happen in the regular course of things + if (empty($this->fbuser)) { + // log badness list($proxy, $ip) = common_client_ip(); @@ -85,50 +69,67 @@ class FacebookfinishloginAction extends Action ); $this->clientError( + // TRANS: Client error displayed when trying to connect to Facebook while not logged in. _m('You must be logged into Facebook to register a local account using Facebook.') ); } + $this->fbuid = $this->fbuser->id; + // OKAY, all is well... proceed to register return true; } - function handle($args) + function handle(array $args=array()) { parent::handle($args); if (common_is_real_login()) { - // User is already logged in, are her accounts already linked? + // This will throw a client exception if the user already + // has some sort of foreign_link to Facebook. - $flink = Foreign_link::getByForeignID($this->fbuid, FACEBOOK_SERVICE); + $this->checkForExistingLink(); - if (!empty($flink)) { + // Possibly reconnect an existing account - // User already has a linked Facebook account and shouldn't be here! + $this->connectUser(); - common_debug( - sprintf( - 'There\'s already a local user %d linked with Facebook user %s.', - $flink->user_id, - $this->fbuid - ) - ); + } else if ($_SERVER['REQUEST_METHOD'] == 'POST') { + $this->handlePost(); + } else { + $this->tryLogin(); + } + } - $this->clientError( - _m('There is already a local account linked with that Facebook account.') - ); + function checkForExistingLink() { - } else { + // User is already logged in, are her accounts already linked? - // Possibly reconnect an existing account + $flink = Foreign_link::getByForeignID($this->fbuid, FACEBOOK_SERVICE); - $this->connectUser(); - } + if (!empty($flink)) { - } else if ($_SERVER['REQUEST_METHOD'] == 'POST') { - $this->handlePost(); - } else { - $this->tryLogin(); + // User already has a linked Facebook account and shouldn't be here! + + $this->clientError( + // TRANS: Client error displayed when trying to connect to a Facebook account that is already linked + // TRANS: in the same StatusNet site. + _m('There is already a local account linked with that Facebook account.') + ); + } + + $cur = common_current_user(); + $flink = Foreign_link::getByUserID($cur->id, FACEBOOK_SERVICE); + + if (!empty($flink)) { + + // There's already a local user linked to this Facebook account. + + $this->clientError( + // TRANS: Client error displayed when trying to connect to a Facebook account that is already linked + // TRANS: in the same StatusNet site. + _m('There is already a local account linked with that Facebook account.') + ); } } @@ -136,8 +137,10 @@ 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. _m('There was a problem with your session token. Try again, please.') ); return; @@ -147,7 +150,8 @@ class FacebookfinishloginAction extends Action if (!$this->boolean('license')) { $this->showForm( - _m('You can\'t register if you don\'t agree to the license.'), + // TRANS: Form validation error displayed when user has not agreed to the license. + _m('You cannot register if you do not agree to the license.'), $this->trimmed('newname') ); return; @@ -164,6 +168,7 @@ class FacebookfinishloginAction extends Action } else { $this->showForm( + // TRANS: Form validation error displayed when an unhandled error occurs. _m('An unknown error has occured.'), $this->trimmed('newname') ); @@ -180,9 +185,10 @@ class FacebookfinishloginAction extends Action $this->element( 'div', 'instructions', - // TRANS: %s is the site name. sprintf( - _m('This is the first time you\'ve logged into %s so we must connect your Facebook to a local account. You can either create a new local account, or connect with an existing local account.'), + // TRANS: Form instructions for connecting to Facebook. + // TRANS: %s is the site name. + _m('This is the first time you have logged into %s so we must connect your Facebook to a local account. You can either create a new local account, or connect with an existing local account.'), common_config('site', 'name') ) ); @@ -209,7 +215,7 @@ class FacebookfinishloginAction extends Action } /** - * @fixme much of this duplicates core code, which is very fragile. + * @todo FIXME: Much of this duplicates core code, which is very fragile. * Should probably be replaced with an extensible mini version of * the core registration form. */ @@ -225,7 +231,7 @@ class FacebookfinishloginAction extends Action 'class' => 'form_settings', 'action' => common_local_url('facebookfinishlogin'))); $this->elementStart('fieldset', array('id' => 'settings_facebook_connect_options')); - // TRANS: Legend. + // TRANS: Fieldset legend. $this->element('legend', null, _m('Connection options')); $this->elementStart('ul', 'form_data'); $this->elementStart('li'); @@ -252,9 +258,10 @@ class FacebookfinishloginAction extends Action $this->elementStart('fieldset'); $this->hidden('token', common_session_token()); $this->element('legend', null, - // TRANS: Legend. + // TRANS: Fieldset legend. _m('Create new account')); $this->element('p', null, + // TRANS: Form instructions. _m('Create a new user with this nickname.')); $this->elementStart('ul', 'form_data'); @@ -265,22 +272,24 @@ class FacebookfinishloginAction extends Action // TRANS: Field label. $this->input('newname', _m('New nickname'), ($this->username) ? $this->username : '', - _m('1-64 lowercase letters or numbers, no punctuation or spaces')); + // TRANS: Field title. + _m('1-64 lowercase letters or numbers, no punctuation or spaces.')); $this->elementEnd('li'); // Hook point for captcha etc Event::handle('EndRegistrationFormData', array($this)); $this->elementEnd('ul'); - // TRANS: Submit button. + // TRANS: Submit button to create a new account. $this->submit('create', _m('BUTTON','Create')); $this->elementEnd('fieldset'); $this->elementStart('fieldset'); - // TRANS: Legend. $this->element('legend', null, + // TRANS: Fieldset legend. _m('Connect existing account')); $this->element('p', null, + // TRANS: Form instructions. _m('If you already have an account, login with your username and password to connect it to your Facebook.')); $this->elementStart('ul', 'form_data'); $this->elementStart('li'); @@ -288,10 +297,11 @@ class FacebookfinishloginAction extends Action $this->input('nickname', _m('Existing nickname')); $this->elementEnd('li'); $this->elementStart('li'); + // TRANS: Field label. $this->password('password', _m('Password')); $this->elementEnd('li'); $this->elementEnd('ul'); - // TRANS: Submit button. + // TRANS: Submit button to connect a Facebook account to an existing StatusNet account. $this->submit('connect', _m('BUTTON','Connect')); $this->elementEnd('fieldset'); @@ -314,7 +324,6 @@ class FacebookfinishloginAction extends Action if (common_config('site', 'closed')) { // TRANS: Client error trying to register with registrations not allowed. $this->clientError(_m('Registration not allowed.')); - return; } $invite = null; @@ -324,49 +333,37 @@ class FacebookfinishloginAction extends Action if (empty($code)) { // TRANS: Client error trying to register with registrations 'invite only'. $this->clientError(_m('Registration not allowed.')); - return; } - $invite = Invitation::staticGet($code); + $invite = Invitation::getKV($code); if (empty($invite)) { // TRANS: Client error trying to register with an invalid invitation code. $this->clientError(_m('Not a valid invitation code.')); - return; } } try { - $nickname = Nickname::normalize($this->trimmed('newname')); + $nickname = Nickname::normalize($this->trimmed('newname'), true); } catch (NicknameException $e) { $this->showForm($e->getMessage()); return; } - if (!User::allowed_nickname($nickname)) { - $this->showForm(_m('Nickname not allowed.')); - return; - } - - if (User::staticGet('nickname', $nickname)) { - $this->showForm(_m('Nickname already in use. Try another one.')); - return; - } - $args = array( - 'nickname' => $nickname, - 'fullname' => $this->fbuser['first_name'] - . ' ' . $this->fbuser['last_name'], - 'homepage' => $this->fbuser['website'], - 'bio' => $this->fbuser['about'], - 'location' => $this->fbuser['location']['name'] + 'nickname' => $nickname, + 'fullname' => $this->fbuser->name, + 'homepage' => $this->fbuser->website, + 'location' => $this->fbuser->location->name ); // It's possible that the email address is already in our // DB. It's a unique key, so we need to check - if ($this->isNewEmail($this->fbuser['email'])) { - $args['email'] = $this->fbuser['email']; - $args['email_confirmed'] = true; + if ($this->isNewEmail($this->fbuser->email)) { + $args['email'] = $this->fbuser->email; + if (isset($this->fuser->verified) && $this->fuser->verified == true) { + $args['email_confirmed'] = true; + } } if (!empty($invite)) { @@ -377,8 +374,8 @@ class FacebookfinishloginAction extends Action $result = $this->flinkUser($user->id, $this->fbuid); if (!$result) { + // TRANS: Server error displayed when connecting to Facebook fails. $this->serverError(_m('Error connecting user to Facebook.')); - return; } // Add a Foreign_user record @@ -395,7 +392,7 @@ class FacebookfinishloginAction extends Action 'Registered new user %s (%d) from Facebook user %s, (fbuid %d)', $user->nickname, $user->id, - $this->fbuser['name'], + $this->fbuser->name, $this->fbuid ), __FILE__ @@ -412,64 +409,67 @@ 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(); - - // fetch the actual picture - $response = $client->get($picUrl); + try { + $picUrl = sprintf( + 'http://graph.facebook.com/%d/picture?type=large', + $this->fbuser->id + ); - if ($response->isOk()) { + // fetch the picture from Facebook + $client = new HTTPClient(); - $finalUrl = $client->getUrl(); + // fetch the actual picture + $response = $client->get($picUrl); - // 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); + if ($response->isOk()) { - $ok = file_put_contents( - Avatar::path($filename), - $response->getBody() - ); + // seems to always be jpeg, but not sure + $tmpname = "facebook-avatar-tmp-" . common_random_hexstr(4); - 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 + + $imagefile = new ImageFile(null, Avatar::path($tmpname)); + $filename = Avatar::filename($user->id, image_type_to_extension($imagefile->preferredType()), + 180, common_timestamp()); + // Previous docs said 180 is the "biggest img we get from Facebook" + $imagefile->resizeTo(Avatar::path($filename, array('width'=>180, 'height'=>180))); + + // No need to keep the temporary file around... + @unlink(Avatar::path($tmpname)); + + $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__ + ); + + // clean up tmp file + } + } } + } catch (Exception $e) { + common_log(LOG_WARNING, 'Couldn\'t save Facebook avatar: ' . $e->getMessage(), __FILE__); + // error isn't fatal, continue } } @@ -479,28 +479,21 @@ class FacebookfinishloginAction extends Action $password = $this->trimmed('password'); if (!common_check_user($nickname, $password)) { + // TRANS: Form validation error displayed when username/password combination is incorrect. $this->showForm(_m('Invalid username or password.')); return; } - $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__ - ); - } + $user = User::getKV('nickname', $nickname); $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); } @@ -508,6 +501,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); } @@ -516,65 +512,37 @@ class FacebookfinishloginAction extends Action $result = $this->flinkUser($user->id, $this->fbuid); if (empty($result)) { + // TRANS: Server error displayed when connecting to Facebook fails. $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)) { + try { + $flink = Foreign_link::getByForeignID($this->fbuid, FACEBOOK_SERVICE); $user = $flink->getUser(); - if (!empty($user)) { - - common_log( - LOG_INFO, - sprintf( - 'Logged in Facebook user %s as user %d (%s)', - $this->fbuid, - $user->nickname, - $user->id - ), - __FILE__ - ); - - common_set_user($user); - common_real_login(true); - $this->goHome($user->nickname); - } - - } else { - - common_debug( + common_log( + LOG_INFO, sprintf( - 'No flink found for fbuid: %s - new user', - $this->fbuid + 'Logged in Facebook user %s as user %d (%s)', + $this->fbuid, + $user->nickname, + $user->id ), __FILE__ ); + 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); + + } catch (NoResultException $e) { $this->showForm(null, $this->bestNewNickname()); } } @@ -597,14 +565,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->credentials = $this->facebook->getAccessToken(); - $flink->created = common_sql_now(); + $flink->user_id = $user_id; + $flink->foreign_id = $fbuid; + $flink->service = FACEBOOK_SERVICE; + $flink->credentials = $this->accessToken; + $flink->created = common_sql_now(); $flink_id = $flink->insert(); @@ -613,59 +579,23 @@ class FacebookfinishloginAction extends Action function bestNewNickname() { - if (!empty($this->fbuser['name'])) { - $nickname = $this->nicknamize($this->fbuser['name']); - if ($this->isNewNickname($nickname)) { - return $nickname; - } + try { + $nickname = Nickname::normalize($this->fbuser->username, true); + return $nickname; + } catch (NicknameException $e) { + // Failed to normalize nickname, but let's try the full name } - // Try the full name - - $fullname = trim($this->fbuser['first_name'] . - ' ' . $this->fbuser['last_name']); - - if (!empty($fullname)) { - $fullname = $this->nicknamize($fullname); - if ($this->isNewNickname($fullname)) { - return $fullname; - } + try { + $nickname = Nickname::normalize($this->fbuser->name, true); + return $nickname; + } catch (NicknameException $e) { + // Any more ideas? Nope. } return null; } - /** - * Given a string, try to make it work as a nickname - */ - function nicknamize($str) - { - $str = preg_replace('/\W/', '', $str); - return strtolower($str); - } - - /* - * Is the desired nickname already taken? - * - * @return boolean result - */ - function isNewNickname($str) - { - if (!Nickname::isValid($str)) { - return false; - } - - if (!User::allowed_nickname($str)) { - return false; - } - - if (User::staticGet('nickname', $str)) { - return false; - } - - return true; - } - /* * Do we already have a user record with this email? * (emails have to be unique but they can change) @@ -677,15 +607,12 @@ class FacebookfinishloginAction extends Action function isNewEmail($email) { // we shouldn't have to validate the format - $result = User::staticGet('email', $email); + $result = User::getKV('email', $email); if (empty($result)) { - common_debug("XXXXXXXXXXXXXXXXXX We've never seen this email before!!!"); return true; } - common_debug("XXXXXXXXXXXXXXXXXX dupe email address!!!!"); return false; } - }