2009-05-20 15:46:11 +09:00
< ? php
/**
2009-08-26 07:29:56 +09:00
* StatusNet , the distributed open - source microblogging tool
2009-05-20 15:46:11 +09:00
*
* Plugin to enable Facebook Connect
*
* PHP version 5
*
* LICENCE : This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU Affero General Public License for more details .
*
* You should have received a copy of the GNU Affero General Public License
* along with this program . If not , see < http :// www . gnu . org / licenses />.
*
* @ category Plugin
2009-08-26 07:29:56 +09:00
* @ package StatusNet
* @ author Zach Copley < zach @ status . net >
* @ copyright 2009 StatusNet , Inc .
2009-05-20 15:46:11 +09:00
* @ license http :// www . fsf . org / licensing / licenses / agpl - 3.0 . html GNU Affero General Public License version 3.0
2009-08-26 07:29:56 +09:00
* @ link http :// status . net /
2009-05-20 15:46:11 +09:00
*/
2010-10-09 03:26:57 +09:00
if ( ! defined ( 'STATUSNET' )) {
exit ( 1 );
}
2009-10-22 02:29:54 +09:00
require_once INSTALLDIR . '/plugins/Facebook/FacebookPlugin.php' ;
2009-05-20 15:46:11 +09:00
2009-05-21 14:43:11 +09:00
class FBConnectauthAction extends Action
2009-05-20 15:46:11 +09:00
{
var $fbuid = null ;
var $fb_fields = null ;
function prepare ( $args ) {
parent :: prepare ( $args );
2009-08-19 07:18:01 +09:00
$this -> fbuid = getFacebook () -> get_loggedin_user ();
2009-05-21 14:43:11 +09:00
2009-08-19 07:18:01 +09:00
if ( $this -> fbuid > 0 ) {
$this -> fb_fields = $this -> getFacebookFields ( $this -> fbuid ,
array ( 'first_name' , 'last_name' , 'name' ));
} else {
2009-08-19 08:41:24 +09:00
list ( $proxy , $ip ) = common_client_ip ();
common_log ( LOG_WARNING , 'Facebook Connect Plugin - ' .
" Failed auth attempt, proxy = $proxy , ip = $ip . " );
2009-12-09 05:17:11 +09:00
$this -> clientError ( _m ( 'You must be logged into Facebook to ' .
'use Facebook Connect.' ));
2009-05-21 14:43:11 +09:00
}
2009-05-20 15:46:11 +09:00
return true ;
}
function handle ( $args )
{
parent :: handle ( $args );
if ( common_is_real_login ()) {
2009-05-28 09:08:00 +09:00
// User is already logged in. Does she already have a linked Facebook acct?
$flink = Foreign_link :: getByForeignID ( $this -> fbuid , FACEBOOK_CONNECT_SERVICE );
2009-07-02 07:47:21 +09:00
if ( ! empty ( $flink )) {
2009-05-28 09:08:00 +09:00
// User already has a linked Facebook account and shouldn't be here
2009-08-19 08:41:24 +09:00
common_debug ( 'Facebook Connect Plugin - ' .
'There is already a local user (' . $flink -> user_id .
') linked with this Facebook (' . $this -> fbuid . ').' );
2009-05-28 09:08:00 +09:00
2009-11-10 04:01:46 +09:00
// We don't want these cookies
2009-05-28 09:08:00 +09:00
getFacebook () -> clear_cookie_state ();
2010-09-19 23:32:19 +09:00
$this -> clientError ( _m ( 'There is already a local user linked with this Facebook account.' ));
2009-05-28 09:08:00 +09:00
} else {
// User came from the Facebook connect settings tab, and
// probably just wants to link/relink their Facebook account
$this -> connectUser ();
}
2009-05-20 15:46:11 +09:00
} else if ( $_SERVER [ 'REQUEST_METHOD' ] == 'POST' ) {
2009-05-21 14:43:11 +09:00
2009-05-20 15:46:11 +09:00
$token = $this -> trimmed ( 'token' );
if ( ! $token || $token != common_session_token ()) {
2009-12-09 05:17:11 +09:00
$this -> showForm ( _m ( 'There was a problem with your session token. Try again, please.' ));
2009-05-20 15:46:11 +09:00
return ;
}
if ( $this -> arg ( 'create' )) {
if ( ! $this -> boolean ( 'license' )) {
2009-12-09 05:17:11 +09:00
$this -> showForm ( _m ( 'You can\'t register if you don\'t agree to the license.' ),
2009-05-20 15:46:11 +09:00
$this -> trimmed ( 'newname' ));
return ;
}
$this -> createNewUser ();
} else if ( $this -> arg ( 'connect' )) {
2009-05-28 09:08:00 +09:00
$this -> connectNewUser ();
2009-05-20 15:46:11 +09:00
} else {
2009-08-19 08:41:24 +09:00
common_debug ( 'Facebook Connect Plugin - ' .
print_r ( $this -> args , true ));
2010-09-19 23:32:19 +09:00
$this -> showForm ( _m ( 'An unknown error has occured.' ),
2009-05-20 15:46:11 +09:00
$this -> trimmed ( 'newname' ));
}
} else {
$this -> tryLogin ();
}
}
function showPageNotice ()
{
if ( $this -> error ) {
$this -> element ( 'div' , array ( 'class' => 'error' ), $this -> error );
} else {
$this -> element ( 'div' , 'instructions' ,
2010-09-19 23:32:19 +09:00
// TRANS: %s is the site name.
2009-12-09 05:17:11 +09:00
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 account, or connect with your existing account, if you have one.' ), common_config ( 'site' , 'name' )));
2009-05-20 15:46:11 +09:00
}
}
function title ()
{
2010-09-19 23:32:19 +09:00
// TRANS: Page title.
2009-12-09 05:17:11 +09:00
return _m ( 'Facebook Account Setup' );
2009-05-20 15:46:11 +09:00
}
function showForm ( $error = null , $username = null )
{
$this -> error = $error ;
$this -> username = $username ;
$this -> showPage ();
}
function showPage ()
{
parent :: showPage ();
}
2010-04-10 02:11:11 +09:00
/**
* @ 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 .
*/
2009-05-20 15:46:11 +09:00
function showContent ()
{
if ( ! empty ( $this -> message_text )) {
$this -> element ( 'p' , null , $this -> message );
return ;
}
$this -> elementStart ( 'form' , array ( 'method' => 'post' ,
2009-05-22 10:53:58 +09:00
'id' => 'form_settings_facebook_connect' ,
2009-05-22 10:43:01 +09:00
'class' => 'form_settings' ,
2009-05-21 14:43:11 +09:00
'action' => common_local_url ( 'FBConnectAuth' )));
2009-05-22 10:53:58 +09:00
$this -> elementStart ( 'fieldset' , array ( 'id' => 'settings_facebook_connect_options' ));
2010-09-19 23:32:19 +09:00
// TRANS: Legend.
2009-12-09 05:17:11 +09:00
$this -> element ( 'legend' , null , _m ( 'Connection options' ));
2009-05-22 10:43:01 +09:00
$this -> elementStart ( 'ul' , 'form_data' );
$this -> elementStart ( 'li' );
2009-05-20 15:46:11 +09:00
$this -> element ( 'input' , array ( 'type' => 'checkbox' ,
'id' => 'license' ,
2009-05-22 10:43:01 +09:00
'class' => 'checkbox' ,
2009-05-20 15:46:11 +09:00
'name' => 'license' ,
'value' => 'true' ));
2009-05-22 10:43:01 +09:00
$this -> elementStart ( 'label' , array ( 'class' => 'checkbox' , 'for' => 'license' ));
2010-09-19 23:32:19 +09:00
// TRANS: %s is the name of the license used by the user for their status updates.
$message = _m ( 'My text and files are available under %s ' .
2010-04-10 02:11:11 +09:00
'except this private data: password, ' .
'email address, IM address, and phone number.' );
$link = '<a href="' .
htmlspecialchars ( common_config ( 'license' , 'url' )) .
'">' .
htmlspecialchars ( common_config ( 'license' , 'title' )) .
'</a>' ;
$this -> raw ( sprintf ( htmlspecialchars ( $message ), $link ));
2009-05-22 10:43:01 +09:00
$this -> elementEnd ( 'label' );
$this -> elementEnd ( 'li' );
$this -> elementEnd ( 'ul' );
2009-05-22 10:53:58 +09:00
$this -> elementStart ( 'fieldset' );
$this -> hidden ( 'token' , common_session_token ());
$this -> element ( 'legend' , null ,
2010-09-19 23:32:19 +09:00
// TRANS: Legend.
2009-12-09 05:17:11 +09:00
_m ( 'Create new account' ));
2009-05-22 10:53:58 +09:00
$this -> element ( 'p' , null ,
2009-12-09 05:17:11 +09:00
_m ( 'Create a new user with this nickname.' ));
2009-05-22 10:53:58 +09:00
$this -> elementStart ( 'ul' , 'form_data' );
$this -> elementStart ( 'li' );
2010-09-19 23:32:19 +09:00
// TRANS: Field label.
2009-12-09 05:17:11 +09:00
$this -> input ( 'newname' , _m ( 'New nickname' ),
2009-05-22 10:53:58 +09:00
( $this -> username ) ? $this -> username : '' ,
2009-12-09 05:17:11 +09:00
_m ( '1-64 lowercase letters or numbers, no punctuation or spaces' ));
2009-05-22 10:53:58 +09:00
$this -> elementEnd ( 'li' );
$this -> elementEnd ( 'ul' );
2010-09-19 23:32:19 +09:00
// TRANS: Submit button.
$this -> submit ( 'create' , _m ( 'BUTTON' , 'Create' ));
2009-05-22 10:43:01 +09:00
$this -> elementEnd ( 'fieldset' );
$this -> elementStart ( 'fieldset' );
2010-09-19 23:32:19 +09:00
// TRANS: Legend.
2009-05-22 10:43:01 +09:00
$this -> element ( 'legend' , null ,
2009-12-09 05:17:11 +09:00
_m ( 'Connect existing account' ));
2009-05-20 15:46:11 +09:00
$this -> element ( 'p' , null ,
2009-12-09 05:17:11 +09:00
_m ( 'If you already have an account, login with your username and password to connect it to your Facebook.' ));
2009-05-22 10:43:01 +09:00
$this -> elementStart ( 'ul' , 'form_data' );
$this -> elementStart ( 'li' );
2010-09-19 23:32:19 +09:00
// TRANS: Field label.
2009-12-09 05:17:11 +09:00
$this -> input ( 'nickname' , _m ( 'Existing nickname' ));
2009-05-22 10:43:01 +09:00
$this -> elementEnd ( 'li' );
$this -> elementStart ( 'li' );
2009-12-09 05:17:11 +09:00
$this -> password ( 'password' , _m ( 'Password' ));
2009-05-22 10:43:01 +09:00
$this -> elementEnd ( 'li' );
$this -> elementEnd ( 'ul' );
2010-09-19 23:32:19 +09:00
// TRANS: Submit button.
$this -> submit ( 'connect' , _m ( 'BUTTON' , 'Connect' ));
2009-05-22 10:53:58 +09:00
$this -> elementEnd ( 'fieldset' );
2009-05-22 10:43:01 +09:00
$this -> elementEnd ( 'fieldset' );
2009-05-20 15:46:11 +09:00
$this -> elementEnd ( 'form' );
}
function message ( $msg )
{
$this -> message_text = $msg ;
$this -> showPage ();
}
function createNewUser ()
{
2011-01-06 05:26:20 +09:00
if ( ! Event :: handle ( 'StartRegistrationTry' , array ( $this ))) {
return ;
}
2009-05-20 15:46:11 +09:00
if ( common_config ( 'site' , 'closed' )) {
2010-09-19 23:32:19 +09:00
// TRANS: Client error trying to register with registrations not allowed.
2009-12-09 05:17:11 +09:00
$this -> clientError ( _m ( 'Registration not allowed.' ));
2009-05-20 15:46:11 +09:00
return ;
}
$invite = null ;
if ( common_config ( 'site' , 'inviteonly' )) {
$code = $_SESSION [ 'invitecode' ];
if ( empty ( $code )) {
2010-09-19 23:32:19 +09:00
// TRANS: Client error trying to register with registrations 'invite only'.
2009-12-09 05:17:11 +09:00
$this -> clientError ( _m ( 'Registration not allowed.' ));
2009-05-20 15:46:11 +09:00
return ;
}
$invite = Invitation :: staticGet ( $code );
if ( empty ( $invite )) {
2010-09-19 23:32:19 +09:00
// TRANS: Client error trying to register with an invalid invitation code.
2009-12-09 05:17:11 +09:00
$this -> clientError ( _m ( 'Not a valid invitation code.' ));
2009-05-20 15:46:11 +09:00
return ;
}
}
2010-11-30 07:15:25 +09:00
try {
$nickname = Nickname :: normalize ( $this -> trimmed ( 'newname' ));
} catch ( NicknameException $e ) {
$this -> showForm ( $e -> getMessage ());
2009-05-20 15:46:11 +09:00
}
if ( ! User :: allowed_nickname ( $nickname )) {
2009-12-09 05:17:11 +09:00
$this -> showForm ( _m ( 'Nickname not allowed.' ));
2009-05-20 15:46:11 +09:00
return ;
}
if ( User :: staticGet ( 'nickname' , $nickname )) {
2009-12-09 05:17:11 +09:00
$this -> showForm ( _m ( 'Nickname already in use. Try another one.' ));
2009-05-20 15:46:11 +09:00
return ;
}
$fullname = trim ( $this -> fb_fields [ 'firstname' ] .
' ' . $this -> fb_fields [ 'lastname' ]);
$args = array ( 'nickname' => $nickname , 'fullname' => $fullname );
if ( ! empty ( $invite )) {
$args [ 'code' ] = $invite -> code ;
}
$user = User :: register ( $args );
$result = $this -> flinkUser ( $user -> id , $this -> fbuid );
if ( ! $result ) {
2009-12-09 05:17:11 +09:00
$this -> serverError ( _m ( 'Error connecting user to Facebook.' ));
2009-05-20 15:46:11 +09:00
return ;
}
common_set_user ( $user );
common_real_login ( true );
2009-08-19 08:41:24 +09:00
common_debug ( 'Facebook Connect Plugin - ' .
" Registered new user $user->id from Facebook user $this->fbuid " );
2009-05-20 15:46:11 +09:00
2011-01-06 05:26:20 +09:00
Event :: handle ( 'EndRegistrationTry' , array ( $this ));
2009-05-20 15:46:11 +09:00
common_redirect ( common_local_url ( 'showstream' , array ( 'nickname' => $user -> nickname )),
303 );
}
2009-05-28 09:08:00 +09:00
function connectNewUser ()
2009-05-20 15:46:11 +09:00
{
$nickname = $this -> trimmed ( 'nickname' );
$password = $this -> trimmed ( 'password' );
if ( ! common_check_user ( $nickname , $password )) {
2009-12-09 05:17:11 +09:00
$this -> showForm ( _m ( 'Invalid username or password.' ));
2009-05-20 15:46:11 +09:00
return ;
}
$user = User :: staticGet ( 'nickname' , $nickname );
2009-08-19 08:41:24 +09:00
if ( ! empty ( $user )) {
common_debug ( 'Facebook Connect Plugin - ' .
" Legit user to connect to Facebook: $nickname " );
2009-05-20 15:46:11 +09:00
}
$result = $this -> flinkUser ( $user -> id , $this -> fbuid );
if ( ! $result ) {
2009-12-09 05:17:11 +09:00
$this -> serverError ( _m ( 'Error connecting user to Facebook.' ));
2009-05-20 15:46:11 +09:00
return ;
}
2009-08-19 08:41:24 +09:00
common_debug ( 'Facebook Connnect Plugin - ' .
" Connected Facebook user $this->fbuid to local user $user->id " );
2009-05-20 15:46:11 +09:00
common_set_user ( $user );
common_real_login ( true );
$this -> goHome ( $user -> nickname );
}
2009-05-28 09:08:00 +09:00
function connectUser ()
{
$user = common_current_user ();
$result = $this -> flinkUser ( $user -> id , $this -> fbuid );
2009-08-19 08:41:24 +09:00
if ( empty ( $result )) {
2009-12-09 05:17:11 +09:00
$this -> serverError ( _m ( 'Error connecting user to Facebook.' ));
2009-05-28 09:08:00 +09:00
return ;
}
2009-08-19 08:41:24 +09:00
common_debug ( 'Facebook Connect Plugin - ' .
" Connected Facebook user $this->fbuid to local user $user->id " );
2009-05-28 09:08:00 +09:00
// Return to Facebook connection settings tab
common_redirect ( common_local_url ( 'FBConnectSettings' ), 303 );
}
2009-05-20 15:46:11 +09:00
function tryLogin ()
{
2009-08-19 08:41:24 +09:00
common_debug ( 'Facebook Connect Plugin - ' .
" Trying login for Facebook user $this->fbuid . " );
2009-05-20 15:46:11 +09:00
2009-05-21 14:43:11 +09:00
$flink = Foreign_link :: getByForeignID ( $this -> fbuid , FACEBOOK_CONNECT_SERVICE );
2009-05-20 15:46:11 +09:00
2009-08-19 08:41:24 +09:00
if ( ! empty ( $flink )) {
2009-05-20 15:46:11 +09:00
$user = $flink -> getUser ();
2009-07-02 07:47:21 +09:00
if ( ! empty ( $user )) {
2009-05-20 15:46:11 +09:00
2009-08-19 08:41:24 +09:00
common_debug ( 'Facebook Connect Plugin - ' .
" Logged in Facebook user $flink->foreign_id as user $user->id ( $user->nickname ) " );
2009-05-20 15:46:11 +09:00
common_set_user ( $user );
common_real_login ( true );
$this -> goHome ( $user -> nickname );
}
} else {
2009-05-21 14:43:11 +09:00
2009-08-19 08:41:24 +09:00
common_debug ( 'Facebook Connect Plugin - ' .
" No flink found for fbuid: $this->fbuid - new user " );
2009-05-21 14:43:11 +09:00
2009-05-20 15:46:11 +09:00
$this -> showForm ( null , $this -> bestNewNickname ());
}
}
function goHome ( $nickname )
{
$url = common_get_returnto ();
if ( $url ) {
2009-11-10 04:01:46 +09:00
// We don't have to return to it again
2009-05-20 15:46:11 +09:00
common_set_returnto ( null );
} else {
$url = common_local_url ( 'all' ,
array ( 'nickname' =>
$nickname ));
}
common_redirect ( $url , 303 );
}
function flinkUser ( $user_id , $fbuid )
{
$flink = new Foreign_link ();
$flink -> user_id = $user_id ;
$flink -> foreign_id = $fbuid ;
2009-05-21 14:43:11 +09:00
$flink -> service = FACEBOOK_CONNECT_SERVICE ;
2009-05-20 15:46:11 +09:00
$flink -> created = common_sql_now ();
$flink_id = $flink -> insert ();
return $flink_id ;
}
function bestNewNickname ()
{
if ( ! empty ( $this -> fb_fields [ 'name' ])) {
$nickname = $this -> nicknamize ( $this -> fb_fields [ 'name' ]);
if ( $this -> isNewNickname ( $nickname )) {
return $nickname ;
}
}
// Try the full name
$fullname = trim ( $this -> fb_fields [ 'firstname' ] .
' ' . $this -> fb_fields [ 'lastname' ]);
if ( ! empty ( $fullname )) {
$fullname = $this -> nicknamize ( $fullname );
if ( $this -> isNewNickname ( $fullname )) {
return $fullname ;
}
}
return null ;
}
2010-09-19 23:32:19 +09:00
/**
* Given a string , try to make it work as a nickname
*/
2009-05-20 15:46:11 +09:00
function nicknamize ( $str )
{
$str = preg_replace ( '/\W/' , '' , $str );
return strtolower ( $str );
}
function isNewNickname ( $str )
{
2010-11-30 07:15:25 +09:00
if ( ! Nickname :: isValid ( $str )) {
2009-05-20 15:46:11 +09:00
return false ;
}
if ( ! User :: allowed_nickname ( $str )) {
return false ;
}
if ( User :: staticGet ( 'nickname' , $str )) {
return false ;
}
return true ;
}
// XXX: Consider moving this to lib/facebookutil.php
function getFacebookFields ( $fb_uid , $fields ) {
try {
2009-05-22 09:54:22 +09:00
$facebook = getFacebook ();
$infos = $facebook -> api_client -> users_getInfo ( $fb_uid , $fields );
2009-05-20 15:46:11 +09:00
if ( empty ( $infos )) {
return null ;
}
return reset ( $infos );
} catch ( Exception $e ) {
2009-08-19 08:41:24 +09:00
common_log ( LOG_WARNING , 'Facebook Connect Plugin - ' .
" Facebook client failure when requesting " .
2009-05-22 09:54:22 +09:00
join ( " , " , $fields ) . " on uid " . $fb_uid .
" : " . $e -> getMessage ());
return null ;
2009-05-20 15:46:11 +09:00
}
}
}