3 * StatusNet, the distributed open-source microblogging tool
5 * Class for doing OAuth authentication against Twitter
9 * LICENCE: This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU Affero General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Affero General Public License for more details.
19 * You should have received a copy of the GNU Affero General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 * @category TwitterauthorizationAction
24 * @author Zach Copely <zach@status.net>
25 * @copyright 2009 StatusNet, Inc.
26 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
27 * @link http://status.net/
30 if (!defined('STATUSNET') && !defined('LACONICA')) {
34 require_once INSTALLDIR . '/plugins/TwitterBridge/twitter.php';
37 * Class for doing OAuth authentication against Twitter
39 * Peforms the OAuth "dance" between StatusNet and Twitter -- requests a token,
40 * authorizes it, and exchanges it for an access token. It also creates a link
41 * (Foreign_link) between the StatusNet user and Twitter user and stores the
42 * access token and secret in the link.
46 * @author Zach Copley <zach@status.net>
47 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
48 * @link http://laconi.ca/
51 class TwitterauthorizationAction extends Action
54 * Initialize class members. Looks for 'oauth_token' parameter.
56 * @param array $args misc. arguments
58 * @return boolean true
60 function prepare($args)
62 parent::prepare($args);
64 $this->oauth_token = $this->arg('oauth_token');
72 * @param array $args is ignored since it's now passed in in prepare()
76 function handle($args)
78 parent::handle($args);
80 if (!common_logged_in()) {
81 $this->clientError(_('Not logged in.'), 403);
84 $user = common_current_user();
85 $flink = Foreign_link::getByUserID($user->id, TWITTER_SERVICE);
87 // If there's already a foreign link record, it means we already
88 // have an access token, and this is unecessary. So go back.
91 common_redirect(common_local_url('twittersettings'));
94 // $this->oauth_token is only populated once Twitter authorizes our
95 // request token. If it's empty we're at the beginning of the auth
98 if (empty($this->oauth_token)) {
99 $this->authorizeRequestToken();
101 $this->saveAccessToken();
106 * Asks Twitter for a request token, and then redirects to Twitter
111 function authorizeRequestToken()
115 // Get a new request token and authorize it
117 $client = new TwitterOAuthClient();
119 $client->getRequestToken(TwitterOAuthClient::$requestTokenURL);
121 // Sock the request token away in the session temporarily
123 $_SESSION['twitter_request_token'] = $req_tok->key;
124 $_SESSION['twitter_request_token_secret'] = $req_tok->secret;
126 $auth_link = $client->getAuthorizeLink($req_tok);
128 } catch (OAuthClientException $e) {
129 $msg = sprintf('OAuth client cURL error - code: %1s, msg: %2s',
130 $e->getCode(), $e->getMessage());
131 $this->serverError(_('Couldn\'t link your Twitter account.'));
134 common_redirect($auth_link);
138 * Called when Twitter returns an authorized request token. Exchanges
139 * it for an access token and stores it.
143 function saveAccessToken()
146 // Check to make sure Twitter returned the same request
147 // token we sent them
149 if ($_SESSION['twitter_request_token'] != $this->oauth_token) {
150 $this->serverError(_('Couldn\'t link your Twitter account.'));
155 $client = new TwitterOAuthClient($_SESSION['twitter_request_token'],
156 $_SESSION['twitter_request_token_secret']);
158 // Exchange the request token for an access token
160 $atok = $client->getAccessToken(TwitterOAuthClient::$accessTokenURL);
162 // Test the access token and get the user's Twitter info
164 $client = new TwitterOAuthClient($atok->key, $atok->secret);
165 $twitter_user = $client->verifyCredentials();
167 } catch (OAuthClientException $e) {
168 $msg = sprintf('OAuth client cURL error - code: %1$s, msg: %2$s',
169 $e->getCode(), $e->getMessage());
170 $this->serverError(_('Couldn\'t link your Twitter account.'));
173 // Save the access token and Twitter user info
175 $this->saveForeignLink($atok, $twitter_user);
177 // Clean up the the mess we made in the session
179 unset($_SESSION['twitter_request_token']);
180 unset($_SESSION['twitter_request_token_secret']);
182 common_redirect(common_local_url('twittersettings'));
186 * Saves a Foreign_link between Twitter user and local user,
187 * which includes the access token and secret.
189 * @param OAuthToken $access_token the access token to save
190 * @param mixed $twitter_user twitter API user object
194 function saveForeignLink($access_token, $twitter_user)
196 $user = common_current_user();
198 $flink = new Foreign_link();
200 $flink->user_id = $user->id;
201 $flink->foreign_id = $twitter_user->id;
202 $flink->service = TWITTER_SERVICE;
204 $creds = TwitterOAuthClient::packToken($access_token);
206 $flink->credentials = $creds;
207 $flink->created = common_sql_now();
209 // Defaults: noticesync on, everything else off
211 $flink->set_flags(true, false, false, false);
213 $flink_id = $flink->insert();
215 if (empty($flink_id)) {
216 common_log_db_error($flink, 'INSERT', __FILE__);
217 $this->serverError(_('Couldn\'t link your Twitter account.'));
220 save_twitter_user($twitter_user->id, $twitter_user->screen_name);