diff --git a/actions/apifriendstimeline.php b/actions/apifriendstimeline.php index dd89f44fe5..dc280b3f3f 100644 --- a/actions/apifriendstimeline.php +++ b/actions/apifriendstimeline.php @@ -19,7 +19,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * - * @category Personal + * @category API * @package StatusNet * @author Zach Copley * @copyright 2009 StatusNet, Inc. @@ -33,6 +33,17 @@ if (!defined('STATUSNET')) { require_once INSTALLDIR.'/lib/apibareauth.php'; +/** + * Returns the most recent notices (default 20) posted by the target user. + * This is the equivalent of 'You and friends' page accessed via Web. + * + * @category API + * @package StatusNet + * @author Zach Copley + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + class ApiFriendsTimelineAction extends ApiBareAuthAction { @@ -86,7 +97,8 @@ class ApiFriendsTimelineAction extends ApiBareAuthAction * @return void */ - function handle($args) { + function handle($args) + { parent::handle($args); $this->showTimeline(); } @@ -104,39 +116,45 @@ class ApiFriendsTimelineAction extends ApiBareAuthAction $title = sprintf(_("%s and friends"), $user->nickname); $taguribase = common_config('integration', 'taguri'); $id = "tag:$taguribase:FriendsTimeline:" . $user->id; - $link = common_local_url('all', - array('nickname' => $user->nickname)); - $subtitle = sprintf(_('Updates from %1$s and friends on %2$s!'), - $user->nickname, $sitename); + $link = common_local_url( + 'all', array('nickname' => $user->nickname) + ); + $subtitle = sprintf( + _('Updates from %1$s and friends on %2$s!'), + $user->nickname, $sitename + ); switch($this->arg('format')) { - case 'xml': - $this->show_xml_timeline($this->notices); - break; - case 'rss': - $this->show_rss_timeline($this->notices, $title, $link, $subtitle); - break; - case 'atom': + case 'xml': + $this->show_xml_timeline($this->notices); + break; + case 'rss': + $this->show_rss_timeline($this->notices, $title, $link, $subtitle); + break; + case 'atom': - $target_id = $this->arg('id'); + $target_id = $this->arg('id'); - if (isset($target_id)) { - $selfuri = common_root_url() . - 'api/statuses/friends_timeline/' . - $target_id . '.atom'; - } else { - $selfuri = common_root_url() . - 'api/statuses/friends_timeline.atom'; - } - $this->show_atom_timeline($this->notices, $title, $id, $link, - $subtitle, null, $selfuri); - break; - case 'json': - $this->show_json_timeline($this->notices); - break; - default: - $this->clientError(_('API method not found!'), $code = 404); - break; + if (isset($target_id)) { + $selfuri = common_root_url() . + 'api/statuses/friends_timeline/' . + $target_id . '.atom'; + } else { + $selfuri = common_root_url() . + 'api/statuses/friends_timeline.atom'; + } + + $this->show_atom_timeline( + $this->notices, $title, $id, $link, + $subtitle, null, $selfuri + ); + break; + case 'json': + $this->show_json_timeline($this->notices); + break; + default: + $this->clientError(_('API method not found!'), $code = 404); + break; } } @@ -151,13 +169,17 @@ class ApiFriendsTimelineAction extends ApiBareAuthAction $notices = array(); if (!empty($this->auth_user) && $this->auth_user->id == $this->user->id) { - $notice = $this->user->noticeInbox(($this->page-1) * $this->count, - $this->count, $this->since_id, - $this->max_id, $this->since); + $notice = $this->user->noticeInbox( + ($this->page-1) * $this->count, + $this->count, $this->since_id, + $this->max_id, $this->since + ); } else { - $notice = $this->user->noticesWithFriends(($this->page-1) * $this->count, - $this->count, $this->since_id, - $this->max_id, $this->since); + $notice = $this->user->noticesWithFriends( + ($this->page-1) * $this->count, + $this->count, $this->since_id, + $this->max_id, $this->since + ); } while ($notice->fetch()) { @@ -168,7 +190,9 @@ class ApiFriendsTimelineAction extends ApiBareAuthAction } /** - * Is this page read-only? + * Is this action read only? + * + * @param array $args other arguments * * @return boolean true */ @@ -181,6 +205,7 @@ class ApiFriendsTimelineAction extends ApiBareAuthAction /** * When was this feed last modified? * + * @return string datestamp of the latest notice in the stream */ function lastModified() @@ -193,7 +218,7 @@ class ApiFriendsTimelineAction extends ApiBareAuthAction } /** - * An entity tag for this page + * An entity tag for this stream * * Returns an Etag based on the action name, language, user ID, and * timestamps of the first and last notice in the timeline @@ -207,12 +232,15 @@ class ApiFriendsTimelineAction extends ApiBareAuthAction $last = count($this->notices) - 1; - return implode(':', + return implode( + ':', array($this->arg('action'), common_language(), $this->user->id, strtotime($this->notices[0]->created), - strtotime($this->notices[$last]->created))) . '"'; + strtotime($this->notices[$last]->created)) + ) + . '"'; } return null; diff --git a/lib/apiauth.php b/lib/apiauth.php index 501d3de10e..c1976f964e 100644 --- a/lib/apiauth.php +++ b/lib/apiauth.php @@ -33,6 +33,16 @@ if (!defined('STATUSNET')) { require_once INSTALLDIR.'/lib/twitterapi.php'; +/** + * Actions extending this class will require auth + * + * @category API + * @package StatusNet + * @author Zach Copley + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + class ApiAuthAction extends TwitterapiAction { /** @@ -46,6 +56,13 @@ class ApiAuthAction extends TwitterapiAction return true; } + /** + * Check for a user specified via HTTP basic auth. If there isn't + * one, try to get one by outputting the basic auth header. + * + * @return boolean true or false + */ + function checkBasicAuthUser() { $this->basicAuthProcessHeader(); @@ -68,8 +85,11 @@ class ApiAuthAction extends TwitterapiAction // basic authentication failed list($proxy, $ip) = common_client_ip(); - common_log(LOG_WARNING, - "Failed API auth attempt, nickname = $nickname, proxy = $proxy, ip = $ip."); + common_log( + LOG_WARNING, + 'Failed API auth attempt, nickname = ' . + "$nickname, proxy = $proxy, ip = $ip." + ); $this->showBasicAuthError(); return false; } @@ -77,16 +97,28 @@ class ApiAuthAction extends TwitterapiAction return true; } + /** + * Read the HTTP headers and set the auth user. Decodes HTTP_AUTHORIZATION + * param to support basic auth when PHP is running in CGI mode. + * + * @return void + */ + function basicAuthProcessHeader() { - if (isset($_SERVER['AUTHORIZATION']) || isset($_SERVER['HTTP_AUTHORIZATION'])) { - $authorization_header = isset($_SERVER['HTTP_AUTHORIZATION'])? $_SERVER['HTTP_AUTHORIZATION'] : $_SERVER['AUTHORIZATION']; + if (isset($_SERVER['AUTHORIZATION']) + || isset($_SERVER['HTTP_AUTHORIZATION']) + ) { + $authorization_header = isset($_SERVER['HTTP_AUTHORIZATION']) + ? $_SERVER['HTTP_AUTHORIZATION'] : $_SERVER['AUTHORIZATION']; } if (isset($_SERVER['PHP_AUTH_USER'])) { $this->auth_user = $_SERVER['PHP_AUTH_USER']; $this->auth_pw = $_SERVER['PHP_AUTH_PW']; - } elseif (isset($authorization_header) && strstr(substr($authorization_header, 0, 5), 'Basic')) { + } elseif (isset($authorization_header) + && strstr(substr($authorization_header, 0, 5), 'Basic')) { + // decode the HTTP_AUTHORIZATION header on php-cgi server self // on fcgid server the header name is AUTHORIZATION @@ -94,6 +126,7 @@ class ApiAuthAction extends TwitterapiAction list($this->auth_user, $this->auth_pw) = explode(':', $auth_hash); // set all to null on a empty basic auth request + if ($this->auth_user == "") { $this->auth_user = null; $this->auth_pw = null; @@ -104,6 +137,13 @@ class ApiAuthAction extends TwitterapiAction } } + /** + * Output an authentication error message. Use XML or JSON if one + * of those formats is specified, otherwise output plain text + * + * @return void + */ + function showBasicAuthError() { header('HTTP/1.1 401 Unauthorized'); @@ -119,7 +159,8 @@ class ApiAuthAction extends TwitterapiAction $this->endXML(); } elseif ($this->arg('format') == 'json') { header('Content-Type: application/json; charset=utf-8'); - $error_array = array('error' => $msg, 'request' => $_SERVER['REQUEST_URI']); + $error_array = array('error' => $msg, + 'request' => $_SERVER['REQUEST_URI']); print(json_encode($error_array)); } else { header('Content-type: text/plain'); @@ -127,5 +168,4 @@ class ApiAuthAction extends TwitterapiAction } } - -} \ No newline at end of file +} diff --git a/lib/apibareauth.php b/lib/apibareauth.php index 8921cddca0..a99d450ecc 100644 --- a/lib/apibareauth.php +++ b/lib/apibareauth.php @@ -35,6 +35,17 @@ if (!defined('STATUSNET')) { require_once INSTALLDIR.'/lib/apiauth.php'; +/** + * Actions extending this class will require auth unless a target + * user ID has been specified + * + * @category API + * @package StatusNet + * @author Zach Copley + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + class ApiBareAuthAction extends ApiAuthAction { /**