]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - plugins/FacebookSSO/FacebookSSOPlugin.php
19d61211d8067b33a5320a886a590609e7645a83
[quix0rs-gnu-social.git] / plugins / FacebookSSO / FacebookSSOPlugin.php
1 <?php
2 /**
3  * StatusNet - the distributed open-source microblogging tool
4  * Copyright (C) 2010, StatusNet, Inc.
5  *
6  * A plugin for integrating Facebook with StatusNet. Includes single-sign-on
7  * and publishing notices to Facebook using Facebook's Graph API.
8  *
9  * PHP version 5
10  *
11  * This program is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Affero General Public License as published by
13  * the Free Software Foundation, either version 3 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU Affero General Public License for more details.
20  *
21  * You should have received a copy of the GNU Affero General Public License
22  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23  *
24  * @category  Pugin
25  * @package   StatusNet
26  * @author    Zach Copley <zach@status.net>
27  * @copyright 2010 StatusNet, Inc.
28  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
29  * @link      http://status.net/
30  */
31
32 if (!defined('STATUSNET')) {
33     exit(1);
34 }
35
36 define("FACEBOOK_SERVICE", 2);
37
38 /**
39  * Main class for Facebook plugin
40  *
41  * @category  Plugin
42  * @package   StatusNet
43  * @author    Zach Copley <zach@status.net>
44  * @copyright 2010 StatusNet, Inc.
45  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
46  * @link      http://status.net/
47  */
48 class FacebookSSOPlugin extends Plugin
49 {
50     public $appId    = null; // Facebook application ID
51     public $apikey   = null; // Facebook API key (for deprecated "Old REST API")
52     public $secret   = null; // Facebook application secret
53     public $facebook = null; // Facebook application instance
54     public $dir      = null; // Facebook SSO plugin dir
55
56     /**
57      * Initializer for this plugin
58      *
59      * Gets an instance of the Facebook API client object
60      *
61      * @return boolean hook value; true means continue processing, false means stop.
62      */
63     function initialize()
64     {
65         $this->facebook = Facebookclient::getFacebook(
66             $this->appId,
67             $this->apikey,
68             $this->secret
69         );
70
71         return true;
72     }
73
74     /**
75      * Load related modules when needed
76      *
77      * @param string $cls Name of the class to be loaded
78      *
79      * @return boolean hook value; true means continue processing, false means stop.
80      */
81     function onAutoload($cls)
82     {
83
84         $dir = dirname(__FILE__);
85
86         //common_debug("class = " . $cls);
87
88         switch ($cls)
89         {
90         case 'Facebook': // Facebook PHP SDK
91             include_once $dir . '/extlib/facebook.php';
92             return false;
93         case 'FacebookloginAction':
94         case 'FacebookfinishloginAction':
95         case 'FacebookadminpanelAction':
96         case 'FacebooksettingsAction':
97         case 'FacebookdeauthorizeAction':
98             include_once $dir . '/actions/' . strtolower(mb_substr($cls, 0, -6)) . '.php';
99             return false;
100         case 'Facebookclient':
101         case 'FacebookQueueHandler':
102             include_once $dir . '/lib/' . strtolower($cls) . '.php';
103             return false;
104         default:
105             return true;
106         }
107
108     }
109
110     /*
111      * Does this $action need the Facebook JavaScripts?
112      */
113     function needsScripts($action)
114     {
115         static $needy = array(
116             'FacebookloginAction',
117             'FacebookfinishloginAction',
118             'FacebookadminpanelAction',
119             'FacebooksettingsAction'
120         );
121
122         if (in_array(get_class($action), $needy)) {
123             return true;
124         } else {
125             return false;
126         }
127     }
128
129     /**
130      * Map URLs to actions
131      *
132      * @param Net_URL_Mapper $m path-to-action mapper
133      *
134      * @return boolean hook value; true means continue processing, false means stop.
135      */
136     function onRouterInitialized($m)
137     {
138         // Always add the admin panel route
139         $m->connect('admin/facebook', array('action' => 'facebookadminpanel'));
140
141         // Only add these routes if an application has been setup on
142         // Facebook for the plugin to use.
143         if ($this->hasApplication()) {
144
145             $m->connect(
146                 'main/facebooklogin',
147                 array('action' => 'facebooklogin')
148             );
149             $m->connect(
150                 'main/facebookfinishlogin',
151                 array('action' => 'facebookfinishlogin')
152             );
153             $m->connect(
154                 'settings/facebook',
155                 array('action' => 'facebooksettings')
156             );
157             $m->connect(
158                 'facebook/deauthorize',
159                 array('action' => 'facebookdeauthorize')
160             );
161
162         }
163
164         return true;
165     }
166
167     /*
168      * Add a login tab for Facebook, but only if there's a Facebook
169      * application defined for the plugin to use.
170      *
171      * @param Action &action the current action
172      *
173      * @return void
174      */
175     function onEndLoginGroupNav(&$action)
176     {
177         $action_name = $action->trimmed('action');
178
179         if ($this->hasApplication()) {
180
181             $action->menuItem(
182                 common_local_url('facebooklogin'),
183                 _m('MENU', 'Facebook'),
184                 // TRANS: Tooltip for menu item "Facebook".
185                 _m('Login or register using Facebook'),
186                'facebooklogin' === $action_name
187             );
188         }
189
190         return true;
191     }
192
193     /**
194      * Add a Facebook tab to the admin panels
195      *
196      * @param Widget $nav Admin panel nav
197      *
198      * @return boolean hook value
199      */
200     function onEndAdminPanelNav($nav)
201     {
202         if (AdminPanelAction::canAdmin('facebook')) {
203
204             $action_name = $nav->action->trimmed('action');
205
206             $nav->out->menuItem(
207                 common_local_url('facebookadminpanel'),
208                 // TRANS: Menu item.
209                 _m('MENU','Facebook'),
210                 // TRANS: Tooltip for menu item "Facebook".
211                 _m('Facebook integration configuration'),
212                 $action_name == 'facebookadminpanel',
213                 'nav_facebook_admin_panel'
214             );
215         }
216
217         return true;
218     }
219
220     /*
221      * Add a tab for user-level Facebook settings
222      *
223      * @param Action &action the current action
224      *
225      * @return void
226      */
227     function onEndConnectSettingsNav(&$action)
228     {
229         if ($this->hasApplication()) {
230             $action_name = $action->trimmed('action');
231
232             $action->menuItem(
233                 common_local_url('facebooksettings'),
234                 // TRANS: Menu item tab.
235                 _m('MENU','Facebook'),
236                 // TRANS: Tooltip for menu item "Facebook".
237                 _m('Facebook settings'),
238                 $action_name === 'facebooksettings'
239             );
240         }
241
242         return true;
243     }
244
245     /*
246      * Is there a Facebook application for the plugin to use?
247      *
248      * Checks to see if a Facebook application ID and secret
249      * have been configured and a valid Facebook API client
250      * object exists.
251      *
252      */
253     function hasApplication()
254     {
255         if (!empty($this->facebook)) {
256
257             $appId  = $this->facebook->getAppId();
258             $secret = $this->facebook->getApiSecret();
259
260             if (!empty($appId) && !empty($secret)) {
261                 return true;
262             }
263
264         }
265
266         return false;
267     }
268
269     /*
270      * Output a Facebook div for the Facebook JavaSsript SDK to use
271      *
272      * @param Action $action the current action
273      *
274      */
275     function onStartShowHeader($action)
276     {
277         // output <div id="fb-root"></div> as close to <body> as possible
278         $action->element('div', array('id' => 'fb-root'));
279         return true;
280     }
281
282     /*
283      * Load the Facebook JavaScript SDK on pages that need them.
284      *
285      * @param Action $action the current action
286      *
287      */
288     function onEndShowScripts($action)
289     {
290         if ($this->needsScripts($action)) {
291
292             $action->script('https://connect.facebook.net/en_US/all.js');
293
294             $script = <<<ENDOFSCRIPT
295 FB.init({appId: %1\$s, session: %2\$s, status: true, cookie: true, xfbml: true});
296
297 $('#facebook_button').bind('click', function(event) {
298
299     event.preventDefault();
300
301     FB.login(function(response) {
302         if (response.session && response.perms) {
303             window.location.href = '%3\$s';
304         } else {
305             // NOP (user cancelled login)
306         }
307     }, {perms:'read_stream,publish_stream,offline_access,user_status,user_location,user_website,email'});
308 });
309 ENDOFSCRIPT;
310
311             $action->inlineScript(
312                 sprintf($script,
313                     json_encode($this->facebook->getAppId()),
314                     json_encode($this->facebook->getSession()),
315                     common_local_url('facebookfinishlogin')
316                 )
317             );
318         }
319     }
320
321     /*
322      * Log the user out of Facebook, per the Facebook authentication guide
323      *
324      * @param Action action the current action
325      */
326     function onEndLogout($action)
327     {
328         if ($this->hasApplication()) {
329             $session = $this->facebook->getSession();
330             $fbuser  = null;
331             $fbuid   = null;
332
333             if ($session) {
334                 try {
335                     $fbuid  = $this->facebook->getUser();
336                     $fbuser = $this->facebook->api('/me');
337                  } catch (FacebookApiException $e) {
338                      common_log(LOG_ERROR, $e, __FILE__);
339                  }
340             }
341
342             if (!empty($fbuser)) {
343
344                 $logoutUrl = $this->facebook->getLogoutUrl(
345                     array('next' => common_local_url('public'))
346                 );
347
348                 common_log(
349                     LOG_INFO,
350                     sprintf(
351                         "Logging user out of Facebook (fbuid = %s)",
352                         $fbuid
353                     ),
354                     __FILE__
355                 );
356                 common_debug("LOGOUT URL = $logoutUrl");
357                 common_redirect($logoutUrl, 303);
358             }
359
360         }
361     }
362
363     /*
364      * Add fbml namespace to our HTML, so Facebook's JavaScript SDK can parse
365      * and render XFBML tags
366      *
367      * @param Action    $action   the current action
368      * @param array     $attrs    array of attributes for the HTML tag
369      *
370      * @return nothing
371      */
372     function onStartHtmlElement($action, $attrs) {
373
374         if ($this->needsScripts($action)) {
375             $attrs = array_merge(
376                 $attrs,
377                 array('xmlns:fb' => 'http://www.facebook.com/2008/fbml')
378             );
379         }
380
381         return true;
382     }
383
384     /**
385      * Add a Facebook queue item for each notice
386      *
387      * @param Notice $notice      the notice
388      * @param array  &$transports the list of transports (queues)
389      *
390      * @return boolean hook return
391      */
392     function onStartEnqueueNotice($notice, &$transports)
393     {
394         if (self::hasApplication() && $notice->isLocal()) {
395             array_push($transports, 'facebook');
396         }
397         return true;
398     }
399
400     /**
401      * Register Facebook notice queue handler
402      *
403      * @param QueueManager $manager
404      *
405      * @return boolean hook return
406      */
407     function onEndInitializeQueueManager($manager)
408     {
409         if (self::hasApplication()) {
410             $manager->connect('facebook', 'FacebookQueueHandler');
411         }
412         return true;
413     }
414
415     /*
416      * Use SSL for Facebook stuff
417      *
418      * @param string $action name
419      * @param boolean $ssl outval to force SSL
420      * @return mixed hook return value
421      */
422     function onSensitiveAction($action, &$ssl)
423     {
424         $sensitive = array(
425             'facebookadminpanel',
426             'facebooksettings',
427             'facebooklogin',
428             'facebookfinishlogin'
429         );
430
431         if (in_array($action, $sensitive)) {
432             $ssl = true;
433             return false;
434         } else {
435             return true;
436         }
437     }
438
439     /*
440      * Add version info for this plugin
441      *
442      * @param array &$versions    plugin version descriptions
443      */
444     function onPluginVersion(&$versions)
445     {
446         $versions[] = array(
447             'name' => 'Facebook Single-Sign-On',
448             'version' => STATUSNET_VERSION,
449             'author' => 'Craig Andrews, Zach Copley',
450             'homepage' => 'http://status.net/wiki/Plugin:FacebookSSO',
451             'rawdescription' =>
452             _m('A plugin for integrating StatusNet with Facebook.')
453         );
454
455         return true;
456     }
457 }