3 * StatusNet - the distributed open-source microblogging tool
4 * Copyright (C) 2010, StatusNet, Inc.
6 * A plugin for single-sign-in (SSO) with Facebook
10 * This program is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU Affero General Public License as published by
12 * the Free Software Foundation, either version 3 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Affero General Public License for more details.
20 * You should have received a copy of the GNU Affero General Public License
21 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25 * @author Zach Copley <zach@status.net>
26 * @copyright 2010 StatusNet, Inc.
27 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
28 * @link http://status.net/
31 if (!defined('STATUSNET')) {
36 * Main class for Facebook single-sign-on plugin
39 * Simple plugins can be implemented as a single module. Others are more complex
40 * and require additional modules; these should use their own directory, like
41 * 'local/plugins/{$name}/'. All files related to the plugin, including images,
42 * JavaScript, CSS, external libraries or PHP modules should go in the plugin
47 * @author Zach Copley <zach@status.net>
48 * @copyright 2010 StatusNet, Inc.
49 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
50 * @link http://status.net/
52 class FacebookSSOPlugin extends Plugin
54 public $appId = null; // Facebook application ID
55 public $secret = null; // Facebook application secret
56 public $facebook = null; // Facebook application instance
57 public $dir = null; // Facebook SSO plugin dir
60 * Initializer for this plugin
62 * Plugins overload this method to do any initialization they need,
63 * like connecting to remote servers or creating paths or so on.
65 * @return boolean hook value; true means continue processing, false means stop.
69 common_debug("XXXXXXXXXXXX " . $this->appId);
70 // Check defaults and configuration for application ID and secret
71 if (empty($this->appId)) {
72 $this->appId = common_config('facebook', 'appid');
75 if (empty($this->secret)) {
76 $this->secret = common_config('facebook', 'secret');
79 if (empty($this->facebook)) {
80 common_debug('instantiating facebook obj');
81 $this->facebook = new Facebook(
83 'appId' => $this->appId,
84 'secret' => $this->secret,
90 common_debug("FACEBOOK = " . var_export($this->facebook, true));
96 * Cleanup for this plugin
98 * Plugins overload this method to do any cleanup they need,
99 * like disconnecting from remote servers or deleting temp files or so on.
101 * @return boolean hook value; true means continue processing, false means stop.
109 * Load related modules when needed
111 * Most non-trivial plugins will require extra modules to do their work. Typically
112 * these include data classes, action classes, widget classes, or external libraries.
114 * This method receives a class name and loads the PHP file related to that class. By
115 * tradition, action classes typically have files named for the action, all lower-case.
116 * Data classes are in files with the data class name, initial letter capitalized.
118 * Note that this method will be called for *all* overloaded classes, not just ones
119 * in this plugin! So, make sure to return true by default to let other plugins, and
120 * the core code, get a chance.
122 * @param string $cls Name of the class to be loaded
124 * @return boolean hook value; true means continue processing, false means stop.
126 function onAutoload($cls)
129 $dir = dirname(__FILE__);
131 //common_debug("class = " . $cls);
136 include_once $dir . '/extlib/facebook.php';
138 case 'FacebookloginAction':
139 case 'FacebookadminpanelAction':
140 include_once $dir . '/' . strtolower(mb_substr($cls, 0, -6)) . '.php';
149 * Map URLs to actions
151 * This event handler lets the plugin map URLs on the site to actions (and
152 * thus an action handler class). Note that the action handler class for an
153 * action will be named 'FoobarAction', where action = 'foobar'. The class
154 * must be loaded in the onAutoload() method.
156 * @param Net_URL_Mapper $m path-to-action mapper
158 * @return boolean hook value; true means continue processing, false means stop.
160 function onRouterInitialized($m)
162 // Always add the admin panel route
163 $m->connect('admin/facebook', array('action' => 'facebookadminpanel'));
165 // Only add these routes if an application has been setup on
166 // Facebook for the plugin to use.
167 if ($this->hasApplication()) {
168 $m->connect('main/facebooklogin', array('action' => 'facebooklogin'));
175 * Add a login tab for Facebook, but only if there's a Facebook
176 * application defined for the plugin to use.
178 * @param Action &action the current action
182 function onEndLoginGroupNav(&$action)
184 $action_name = $action->trimmed('action');
186 if ($this->hasApplication()) {
189 common_local_url('facebooklogin'),
190 _m('MENU', 'Facebook'),
191 // TRANS: Tooltip for menu item "Facebook".
192 _m('Login or register using Facebook'),
193 'facebooklogin' === $action_name
201 * Add a Facebook tab to the admin panels
203 * @param Widget $nav Admin panel nav
205 * @return boolean hook value
207 function onEndAdminPanelNav($nav)
209 if (AdminPanelAction::canAdmin('facebook')) {
211 $action_name = $nav->action->trimmed('action');
214 common_local_url('facebookadminpanel'),
216 _m('MENU','Facebook'),
217 // TRANS: Tooltip for menu item "Facebook".
218 _m('Facebook integration configuration'),
219 $action_name == 'facebookadminpanel',
220 'nav_facebook_admin_panel'
228 * Is there a Facebook application for the plugin to use?
230 function hasApplication()
232 if (!empty($this->appId) && !empty($this->secret)) {
239 function onStartShowHeader($action)
241 // output <div id="fb-root"></div> as close to <body> as possible
242 $action->element('div', array('id' => 'fb-root'));
244 $session = $this->facebook->getSession();
245 $dir = dirname(__FILE__);
248 $script = <<<ENDOFSCRIPT
249 window.fbAsyncInit = function() {
253 session : %s, // don't refetch the session when PHP already has it
254 status : true, // check login status
255 cookie : true, // enable cookies to allow the server to access the session
256 xfbml : true // parse XFBML
259 // whenever the user logs in, refresh the page
263 window.location.reload();
269 var e = document.createElement('script');
270 e.src = document.location.protocol + '//connect.facebook.net/en_US/all.js';
272 document.getElementById('fb-root').appendChild(e);
276 $action->inlineScript(
278 json_encode($this->appId),
279 json_encode($this->session)
286 function onStartHtmlElement($action, $attrs) {
287 $attrs = array_merge($attrs, array('xmlns:fb' => 'http://www.facebook.com/2008/fbml'));
291 function onPluginVersion(&$versions)
293 $versions[] = array('name' => 'Facebook Single-Sign-On',
294 'version' => STATUSNET_VERSION,
295 'author' => 'Zach Copley',
296 'homepage' => 'http://status.net/wiki/Plugin:FacebookSSO',
298 _m('A plugin for single-sign-on with Facebook.'));