diff options
Diffstat (limited to 'actions')
49 files changed, 1149 insertions, 2554 deletions
diff --git a/actions/accesstoken.php b/actions/accesstoken.php index c99aaeded..76bd40473 100644 --- a/actions/accesstoken.php +++ b/actions/accesstoken.php @@ -1,6 +1,6 @@ <?php /** - * Access token class. + * Access token class * * PHP version 5 * @@ -32,10 +32,11 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } +require_once INSTALLDIR.'/extlib/libomb/service_provider.php'; require_once INSTALLDIR.'/lib/omb.php'; /** - * Access token class. + * Access token class * * @category Action * @package StatusNet @@ -47,28 +48,23 @@ require_once INSTALLDIR.'/lib/omb.php'; class AccesstokenAction extends Action { /** - * Class handler. + * Class handler * * @param array $args query arguments * - * @return boolean false if user doesn't exist - */ + * @return nothing + * + **/ function handle($args) { parent::handle($args); try { - common_debug('getting request from env variables', __FILE__); - common_remove_magic_from_request(); - $req = OAuthRequest::from_request('POST', common_local_url('accesstoken')); - common_debug('getting a server', __FILE__); - $server = omb_oauth_server(); - common_debug('fetching the access token', __FILE__); - $token = $server->fetch_access_token($req); - common_debug('got this token: "'.print_r($token, true).'"', __FILE__); - common_debug('printing the access token', __FILE__); - print $token; - } catch (OAuthException $e) { + $srv = new OMB_Service_Provider(null, omb_oauth_datastore(), + omb_oauth_server()); + $srv->writeAccessToken(); + } catch (Exception $e) { $this->serverError($e->getMessage()); } } } +?> diff --git a/actions/all.php b/actions/all.php index bfde3a7e4..f1786462e 100644 --- a/actions/all.php +++ b/actions/all.php @@ -1,5 +1,5 @@ <?php -/* +/** * StatusNet - the distributed open-source microblogging tool * Copyright (C) 2008, 2009, StatusNet, Inc. * @@ -15,9 +15,25 @@ * * 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 Actions + * @package Actions + * @author Evan Prodromou <evan@status.net> + * @author Mike Cochrane <mikec@mikenz.geek.nz> + * @author Robin Millette <millette@controlyourself.ca> + * @author Adrian Lang <mail@adrianlang.de> + * @author Meitar Moscovitz <meitarm@gmail.com> + * @author Sarven Capadisli <csarven@status.net> + * @author Craig Andrews <candrews@integralblue.com> + * @author Jeffery To <jeffery.to@gmail.com> + * @author Zach Copley <zach@controlyourself.ca> + * @license GNU Affero General Public License http://www.gnu.org/licenses/ + * @link http://status.net */ -if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } +if (!defined('STATUSNET') && !defined('LACONICA')) { + exit(1); +} require_once INSTALLDIR.'/lib/personalgroupnav.php'; require_once INSTALLDIR.'/lib/noticelist.php'; @@ -43,8 +59,8 @@ class AllAction extends ProfileAction $this->notice = $this->user->noticesWithFriends(($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1); } - if($this->page > 1 && $this->notice->N == 0){ - $this->serverError(_('No such page'),$code=404); + if ($this->page > 1 && $this->notice->N == 0) { + $this->serverError(_('No such page'), $code = 404); } return true; @@ -73,20 +89,33 @@ class AllAction extends ProfileAction function getFeeds() { - return array(new Feed(Feed::RSS1, - common_local_url('allrss', array('nickname' => - $this->user->nickname)), - sprintf(_('Feed for friends of %s (RSS 1.0)'), $this->user->nickname)), - new Feed(Feed::RSS2, - common_local_url('api', array('apiaction' => 'statuses', - 'method' => 'friends_timeline', - 'argument' => $this->user->nickname.'.rss')), - sprintf(_('Feed for friends of %s (RSS 2.0)'), $this->user->nickname)), - new Feed(Feed::ATOM, - common_local_url('api', array('apiaction' => 'statuses', - 'method' => 'friends_timeline', - 'argument' => $this->user->nickname.'.atom')), - sprintf(_('Feed for friends of %s (Atom)'), $this->user->nickname))); + return array( + new Feed(Feed::RSS1, + common_local_url( + 'allrss', array( + 'nickname' => + $this->user->nickname) + ), + sprintf(_('Feed for friends of %s (RSS 1.0)'), $this->user->nickname)), + new Feed(Feed::RSS2, + common_local_url( + 'api', array( + 'apiaction' => 'statuses', + 'method' => 'friends_timeline', + 'argument' => $this->user->nickname.'.rss' + ) + ), + sprintf(_('Feed for friends of %s (RSS 2.0)'), $this->user->nickname)), + new Feed(Feed::ATOM, + common_local_url( + 'api', array( + 'apiaction' => 'statuses', + 'method' => 'friends_timeline', + 'argument' => $this->user->nickname.'.atom' + ) + ), + sprintf(_('Feed for friends of %s (Atom)'), $this->user->nickname)) + ); } function showLocalNav() @@ -106,11 +135,8 @@ class AllAction extends ProfileAction } else { $message .= sprintf(_('You can try to [nudge %s](../%s) from his profile or [post something to his or her attention](%%%%action.newnotice%%%%?status_textarea=%s).'), $this->user->nickname, $this->user->nickname, '@' . $this->user->nickname); } - } - else { - $message .= sprintf(_('Why not [register an account](%%%%action.%s%%%%) and then nudge %s or post a notice to his or her attention.'), - (!common_config('site','openidonly')) ? 'register' : 'openidlogin', - $this->user->nickname); + } else { + $message .= sprintf(_('Why not [register an account](%%%%action.register%%%%) and then nudge %s or post a notice to his or her attention.'), $this->user->nickname); } $this->elementStart('div', 'guide'); @@ -128,17 +154,19 @@ class AllAction extends ProfileAction $this->showEmptyListMessage(); } - $this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE, - $this->page, 'all', array('nickname' => $this->user->nickname)); + $this->pagination( + $this->page > 1, $cnt > NOTICES_PER_PAGE, + $this->page, 'all', array('nickname' => $this->user->nickname) + ); } function showPageTitle() { $user =& common_current_user(); if ($user && ($user->id == $this->user->id)) { - $this->element('h1', NULL, _("You and friends")); + $this->element('h1', null, _("You and friends")); } else { - $this->element('h1', NULL, sprintf(_('%s and friends'), $this->user->nickname)); + $this->element('h1', null, sprintf(_('%s and friends'), $this->user->nickname)); } } diff --git a/actions/allrss.php b/actions/allrss.php index 57efb73f0..28b1be27d 100644 --- a/actions/allrss.php +++ b/actions/allrss.php @@ -68,6 +68,7 @@ class AllrssAction extends Rss10Action $this->clientError(_('No such user.')); return false; } else { + $this->notices = $this->getNotices($this->limit); return true; } } diff --git a/actions/api.php b/actions/api.php index 3705d035c..1bc90de11 100644 --- a/actions/api.php +++ b/actions/api.php @@ -1,5 +1,5 @@ <?php -/* +/** * StatusNet - the distributed open-source microblogging tool * Copyright (C) 2008, 2009, StatusNet, Inc. * @@ -15,9 +15,27 @@ * * 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 Actions + * @package Actions + * @author Evan Prodromou <evan@status.net> + * @author Brenda Wallace <shiny@cpan.org> + * @author Jeffery To <jeffery.to@gmail.com> + * @author Robin Millette <millette@controlyourself.ca> + * @author Tom Adams <tom@holizz.com> + * @author Christopher Vollick <psycotica0@gmail.com> + * @author CiaranG <ciaran@ciarang.com> + * @author Craig Andrews <candrews@integralblue.com> + * @author Gina Haeussge <osd@foosel.net> + * @author Mike Cochrane <mikec@mikenz.geek.nz> + * @author Sarven Capadisli <csarven@status.net> + * @license GNU Affero General Public License http://www.gnu.org/licenses/ + * @link http://status.net */ -if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } +if (!defined('STATUSNET') && !defined('LACONICA')) { + exit(1); +} class ApiAction extends Action { @@ -37,7 +55,7 @@ class ApiAction extends Action $this->api_action = $this->arg('apiaction'); $method = $this->arg('method'); $argument = $this->arg('argument'); - $this->basic_auth_process_header(); + $this->basic_auth_process_header(); if (isset($argument)) { $cmdext = explode('.', $argument); @@ -46,7 +64,7 @@ class ApiAction extends Action $this->content_type = strtolower($cmdext[1]); } else { - # Requested format / content-type will be an extension on the method + //Requested format / content-type will be an extension on the method $cmdext = explode('.', $method); $this->api_method = $cmdext[0]; $this->content_type = strtolower($cmdext[1]); @@ -55,10 +73,10 @@ class ApiAction extends Action if ($this->requires_auth()) { if (!isset($this->auth_user)) { - # This header makes basic auth go + //This header makes basic auth go header('WWW-Authenticate: Basic realm="StatusNet API"'); - # If the user hits cancel -- bam! + //If the user hits cancel -- bam! $this->show_basic_auth_error(); } else { $nickname = $this->auth_user; @@ -69,7 +87,7 @@ class ApiAction extends Action $this->user = $user; $this->process_command(); } else { - # basic authentication failed + //basic authentication failed list($proxy, $ip) = common_client_ip(); common_log(LOG_WARNING, "Failed API auth attempt, nickname = $nickname, proxy = $proxy, ip = $ip."); @@ -84,7 +102,7 @@ class ApiAction extends Action if ($user) { $this->user = $user; } - # Twitter doesn't throw an error if the user isn't found + //Twitter doesn't throw an error if the user isn't found } $this->process_command(); @@ -97,7 +115,7 @@ class ApiAction extends Action $actionfile = INSTALLDIR."/actions/$action.php"; if (file_exists($actionfile)) { - require_once($actionfile); + include_once $actionfile; $action_class = ucfirst($action)."Action"; $action_obj = new $action_class(); @@ -113,10 +131,10 @@ class ApiAction extends Action call_user_func(array($action_obj, $this->api_method), $_REQUEST, $apidata); } else { - $this->clientError("API method not found!", $code=404); + $this->clientError("API method not found!", $code = 404); } } else { - $this->clientError("API method not found!", $code=404); + $this->clientError("API method not found!", $code = 404); } } @@ -185,10 +203,11 @@ class ApiAction extends Action $user_id = $this->arg('user_id'); $screen_name = $this->arg('screen_name'); - if (empty($this->api_arg) && - empty($id) && - empty($user_id) && - empty($screen_name)) { + if (empty($this->api_arg) + && empty($id) + && empty($user_id) + && empty($screen_name) + ) { return true; } else { return false; @@ -209,35 +228,29 @@ class ApiAction extends Action function basic_auth_process_header() { - 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') ) - { - // decode the HTTP_AUTHORIZATION header on php-cgi server self - // on fcgid server the header name is AUTHORIZATION - - $auth_hash = base64_decode( substr($authorization_header, 6) ); - 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; - } - } - else - { - $this->auth_user = NULL; - $this->auth_pw = NULL; - } + 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')) { + // decode the HTTP_AUTHORIZATION header on php-cgi server self + // on fcgid server the header name is AUTHORIZATION + + $auth_hash = base64_decode(substr($authorization_header, 6)); + 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; + } + } else { + $this->auth_user = null; + $this->auth_pw = null; + } } function show_basic_auth_error() @@ -253,7 +266,7 @@ class ApiAction extends Action $this->element('request', null, $_SERVER['REQUEST_URI']); $this->elementEnd('hash'); $this->endXML(); - } else if ($this->content_type == 'json') { + } else if ($this->content_type == 'json') { header('Content-Type: application/json; charset=utf-8'); $error_array = array('error' => $msg, 'request' => $_SERVER['REQUEST_URI']); print(json_encode($error_array)); diff --git a/actions/confirmaddress.php b/actions/confirmaddress.php index 201694286..6fd74f3ff 100644 --- a/actions/confirmaddress.php +++ b/actions/confirmaddress.php @@ -67,11 +67,7 @@ class ConfirmaddressAction extends Action parent::handle($args); if (!common_logged_in()) { common_set_returnto($this->selfUrl()); - if (!common_config('site', 'openidonly')) { - common_redirect(common_local_url('login')); - } else { - common_redirect(common_local_url('openidlogin')); - } + common_redirect(common_local_url('login')); return; } $code = $this->trimmed('code'); diff --git a/actions/deletenotice.php b/actions/deletenotice.php index 3d040f2fa..4a48a9c34 100644 --- a/actions/deletenotice.php +++ b/actions/deletenotice.php @@ -32,15 +32,45 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } -require_once INSTALLDIR.'/lib/deleteaction.php'; - -class DeletenoticeAction extends DeleteAction +class DeletenoticeAction extends Action { - var $error = null; + var $error = null; + var $user = null; + var $notice = null; + var $profile = null; + var $user_profile = null; + + function prepare($args) + { + parent::prepare($args); + + $this->user = common_current_user(); + $notice_id = $this->trimmed('notice'); + $this->notice = Notice::staticGet($notice_id); + + if (!$this->notice) { + common_user_error(_('No such notice.')); + exit; + } + + $this->profile = $this->notice->getProfile(); + $this->user_profile = $this->user->getProfile(); + + return true; + } function handle($args) { parent::handle($args); + + if (!common_logged_in()) { + common_user_error(_('Not logged in.')); + exit; + } else if ($this->notice->profile_id != $this->user_profile->id && + !$this->user->hasRight(Right::deleteOthersNotice)) { + common_user_error(_('Can\'t delete this notice.')); + exit; + } // XXX: Ajax! if ($_SERVER['REQUEST_METHOD'] == 'POST') { diff --git a/actions/doc.php b/actions/doc.php index 68295234c..836f039d3 100644 --- a/actions/doc.php +++ b/actions/doc.php @@ -58,12 +58,24 @@ class DocAction extends Action function handle($args) { parent::handle($args); - $this->title = $this->trimmed('title'); - $this->filename = INSTALLDIR.'/doc-src/'.$this->title; - if (!file_exists($this->filename)) { - $this->clientError(_('No such document.')); - return; + + $this->title = $this->trimmed('title'); + $this->output = null; + + if (Event::handle('StartLoadDoc', array(&$this->title, &$this->output))) { + + $this->filename = INSTALLDIR.'/doc-src/'.$this->title; + if (!file_exists($this->filename)) { + $this->clientError(_('No such document.')); + return; + } + + $c = file_get_contents($this->filename); + $this->output = common_markup_to_html($c); + + Event::handle('EndLoadDoc', array($this->title, &$this->output)); } + $this->showPage(); } @@ -93,9 +105,7 @@ class DocAction extends Action */ function showContent() { - $c = file_get_contents($this->filename); - $output = common_markup_to_html($c); - $this->raw($output); + $this->raw($this->output); } /** diff --git a/actions/editgroup.php b/actions/editgroup.php index b8dac31cb..5dd039f8a 100644 --- a/actions/editgroup.php +++ b/actions/editgroup.php @@ -202,8 +202,8 @@ class EditgroupAction extends GroupDesignAction } else if (!is_null($fullname) && mb_strlen($fullname) > 255) { $this->showForm(_('Full name is too long (max 255 chars).')); return; - } else if (!is_null($description) && mb_strlen($description) > 140) { - $this->showForm(_('description is too long (max 140 chars).')); + } else if (User_group::descriptionTooLong($description)) { + $this->showForm(sprintf(_('description is too long (max %d chars).'), User_group::maxDescription())); return; } else if (!is_null($location) && mb_strlen($location) > 255) { $this->showForm(_('Location is too long (max 255 chars).')); diff --git a/actions/favorited.php b/actions/favorited.php index 5ba508cdf..150b67b0b 100644 --- a/actions/favorited.php +++ b/actions/favorited.php @@ -153,8 +153,7 @@ class FavoritedAction extends Action $message .= _('Be the first to add a notice to your favorites by clicking the fave button next to any notice you like.'); } else { - $message .= sprintf(_('Why not [register an account](%%%%action.%s%%%%) and be the first to add a notice to your favorites!'), - (!common_config('site','openidonly')) ? 'register' : 'openidlogin'); + $message .= _('Why not [register an account](%%action.register%%) and be the first to add a notice to your favorites!'); } $this->elementStart('div', 'guide'); diff --git a/actions/favoritesrss.php b/actions/favoritesrss.php index 2d5ce9854..62f06e841 100644 --- a/actions/favoritesrss.php +++ b/actions/favoritesrss.php @@ -50,11 +50,11 @@ require_once INSTALLDIR.'/lib/rssaction.php'; */ class FavoritesrssAction extends Rss10Action { - + /** The user whose favorites to display */ - + var $user = null; - + /** * Find the user to display by supplied nickname * @@ -66,7 +66,7 @@ class FavoritesrssAction extends Rss10Action function prepare($args) { parent::prepare($args); - + $nickname = $this->trimmed('nickname'); $this->user = User::staticGet('nickname', $nickname); @@ -74,10 +74,11 @@ class FavoritesrssAction extends Rss10Action $this->clientError(_('No such user.')); return false; } else { + $this->notices = $this->getNotices($this->limit); return true; } } - + /** * Get notices * diff --git a/actions/finishaddopenid.php b/actions/finishaddopenid.php deleted file mode 100644 index b6de4f244..000000000 --- a/actions/finishaddopenid.php +++ /dev/null @@ -1,185 +0,0 @@ -<?php -/** - * StatusNet, the distributed open-source microblogging tool - * - * Complete adding an OpenID - * - * 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 Settings - * @package StatusNet - * @author Evan Prodromou <evan@status.net> - * @copyright 2008-2009 StatusNet, Inc. - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://status.net/ - */ - -if (!defined('STATUSNET') && !defined('LACONICA')) { - exit(1); -} - -require_once INSTALLDIR.'/lib/openid.php'; - -/** - * Complete adding an OpenID - * - * Handle the return from an OpenID verification - * - * @category Settings - * @package StatusNet - * @author Evan Prodromou <evan@status.net> - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://status.net/ - */ - -class FinishaddopenidAction extends Action -{ - var $msg = null; - - /** - * Handle the redirect back from OpenID confirmation - * - * Check to see if the user's logged in, and then try - * to use the OpenID login system. - * - * @param array $args $_REQUEST arguments - * - * @return void - */ - - function handle($args) - { - parent::handle($args); - if (!common_logged_in()) { - $this->clientError(_('Not logged in.')); - } else { - $this->tryLogin(); - } - } - - /** - * Try to log in using OpenID - * - * Check the OpenID for validity; potentially store it. - * - * @return void - */ - - function tryLogin() - { - $consumer =& oid_consumer(); - - $response = $consumer->complete(common_local_url('finishaddopenid')); - - if ($response->status == Auth_OpenID_CANCEL) { - $this->message(_('OpenID authentication cancelled.')); - return; - } else if ($response->status == Auth_OpenID_FAILURE) { - // Authentication failed; display the error message. - $this->message(sprintf(_('OpenID authentication failed: %s'), - $response->message)); - } else if ($response->status == Auth_OpenID_SUCCESS) { - - $display = $response->getDisplayIdentifier(); - $canonical = ($response->endpoint && $response->endpoint->canonicalID) ? - $response->endpoint->canonicalID : $display; - - $sreg_resp = Auth_OpenID_SRegResponse::fromSuccessResponse($response); - - if ($sreg_resp) { - $sreg = $sreg_resp->contents(); - } - - $cur =& common_current_user(); - - $other = oid_get_user($canonical); - - if ($other) { - if ($other->id == $cur->id) { - $this->message(_('You already have this OpenID!')); - } else { - $this->message(_('Someone else already has this OpenID.')); - } - return; - } - - // start a transaction - - $cur->query('BEGIN'); - - $result = oid_link_user($cur->id, $canonical, $display); - - if (!$result) { - $this->message(_('Error connecting user.')); - return; - } - if ($sreg) { - if (!oid_update_user($cur, $sreg)) { - $this->message(_('Error updating profile')); - return; - } - } - - // success! - - $cur->query('COMMIT'); - - oid_set_last($display); - - common_redirect(common_local_url('openidsettings'), 303); - } - } - - /** - * Show a failure message - * - * Something went wrong. Save the message, and show the page. - * - * @param string $msg Error message to show - * - * @return void - */ - - function message($msg) - { - $this->message = $msg; - $this->showPage(); - } - - /** - * Title of the page - * - * @return string title - */ - - function title() - { - return _('OpenID Login'); - } - - /** - * Show error message - * - * @return void - */ - - function showPageNotice() - { - if ($this->message) { - $this->element('p', 'error', $this->message); - } - } -} diff --git a/actions/finishopenidlogin.php b/actions/finishopenidlogin.php deleted file mode 100644 index 9ac036985..000000000 --- a/actions/finishopenidlogin.php +++ /dev/null @@ -1,497 +0,0 @@ -<?php -/* - * StatusNet - the distributed open-source microblogging tool - * Copyright (C) 2008, 2009, StatusNet, Inc. - * - * 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/>. - */ - -if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } - -require_once(INSTALLDIR.'/lib/openid.php'); - -class FinishopenidloginAction extends Action -{ - var $error = null; - var $username = null; - var $message = null; - - function handle($args) - { - parent::handle($args); - if (!common_config('openid', 'enabled')) { - common_redirect(common_local_url('login')); - } else if (common_is_real_login()) { - $this->clientError(_('Already logged in.')); - } else if ($_SERVER['REQUEST_METHOD'] == 'POST') { - $token = $this->trimmed('token'); - if (!$token || $token != common_session_token()) { - $this->showForm(_('There was a problem with your session token. Try again, please.')); - return; - } - if ($this->arg('create')) { - if (!$this->boolean('license')) { - $this->showForm(_('You can\'t register if you don\'t agree to the license.'), - $this->trimmed('newname')); - return; - } - $this->createNewUser(); - } else if ($this->arg('connect')) { - $this->connectUser(); - } else { - common_debug(print_r($this->args, true), __FILE__); - $this->showForm(_('Something weird happened.'), - $this->trimmed('newname')); - } - } else { - $this->tryLogin(); - } - } - - function showPageNotice() - { - if ($this->error) { - $this->element('div', array('class' => 'error'), $this->error); - } else { - $this->element('div', 'instructions', - sprintf(_('This is the first time you\'ve logged into %s so we must connect your OpenID 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'))); - } - } - - function title() - { - return _('OpenID Account Setup'); - } - - function showForm($error=null, $username=null) - { - $this->error = $error; - $this->username = $username; - - $this->showPage(); - } - - function showContent() - { - if (!empty($this->message_text)) { - $this->element('div', array('class' => 'error'), $this->message_text); - return; - } - - $this->elementStart('form', array('method' => 'post', - 'id' => 'account_connect', - 'action' => common_local_url('finishopenidlogin'))); - $this->hidden('token', common_session_token()); - $this->element('h2', null, - _('Create new account')); - $this->element('p', null, - _('Create a new user with this nickname.')); - $this->input('newname', _('New nickname'), - ($this->username) ? $this->username : '', - _('1-64 lowercase letters or numbers, no punctuation or spaces')); - $this->elementStart('p'); - $this->element('input', array('type' => 'checkbox', - 'id' => 'license', - 'name' => 'license', - 'value' => 'true')); - $this->text(_('My text and files are available under ')); - $this->element('a', array('href' => common_config('license', 'url')), - common_config('license', 'title')); - $this->text(_(' except this private data: password, email address, IM address, phone number.')); - $this->elementEnd('p'); - $this->submit('create', _('Create')); - $this->element('h2', null, - _('Connect existing account')); - $this->element('p', null, - _('If you already have an account, login with your username and password to connect it to your OpenID.')); - $this->input('nickname', _('Existing nickname')); - $this->password('password', _('Password')); - $this->submit('connect', _('Connect')); - $this->elementEnd('form'); - } - - function tryLogin() - { - $consumer = oid_consumer(); - - $response = $consumer->complete(common_local_url('finishopenidlogin')); - - if ($response->status == Auth_OpenID_CANCEL) { - $this->message(_('OpenID authentication cancelled.')); - return; - } else if ($response->status == Auth_OpenID_FAILURE) { - // Authentication failed; display the error message. - $this->message(sprintf(_('OpenID authentication failed: %s'), $response->message)); - } else if ($response->status == Auth_OpenID_SUCCESS) { - // This means the authentication succeeded; extract the - // identity URL and Simple Registration data (if it was - // returned). - $display = $response->getDisplayIdentifier(); - $canonical = ($response->endpoint->canonicalID) ? - $response->endpoint->canonicalID : $response->getDisplayIdentifier(); - - $sreg_resp = Auth_OpenID_SRegResponse::fromSuccessResponse($response); - - if ($sreg_resp) { - $sreg = $sreg_resp->contents(); - } - - $user = oid_get_user($canonical); - - if ($user) { - oid_set_last($display); - # XXX: commented out at @edd's request until better - # control over how data flows from OpenID provider. - # oid_update_user($user, $sreg); - common_set_user($user); - common_real_login(true); - if (isset($_SESSION['openid_rememberme']) && $_SESSION['openid_rememberme']) { - common_rememberme($user); - } - unset($_SESSION['openid_rememberme']); - $this->goHome($user->nickname); - } else { - $this->saveValues($display, $canonical, $sreg); - $this->showForm(null, $this->bestNewNickname($display, $sreg)); - } - } - } - - function message($msg) - { - $this->message_text = $msg; - $this->showPage(); - } - - function saveValues($display, $canonical, $sreg) - { - common_ensure_session(); - $_SESSION['openid_display'] = $display; - $_SESSION['openid_canonical'] = $canonical; - $_SESSION['openid_sreg'] = $sreg; - } - - function getSavedValues() - { - return array($_SESSION['openid_display'], - $_SESSION['openid_canonical'], - $_SESSION['openid_sreg']); - } - - function createNewUser() - { - # FIXME: save invite code before redirect, and check here - - if (common_config('site', 'closed')) { - $this->clientError(_('Registration not allowed.')); - return; - } - - $invite = null; - - if (common_config('site', 'inviteonly')) { - $code = $_SESSION['invitecode']; - if (empty($code)) { - $this->clientError(_('Registration not allowed.')); - return; - } - - $invite = Invitation::staticGet($code); - - if (empty($invite)) { - $this->clientError(_('Not a valid invitation code.')); - return; - } - } - - $nickname = $this->trimmed('newname'); - - if (!Validate::string($nickname, array('min_length' => 1, - 'max_length' => 64, - 'format' => NICKNAME_FMT))) { - $this->showForm(_('Nickname must have only lowercase letters and numbers and no spaces.')); - return; - } - - if (!User::allowed_nickname($nickname)) { - $this->showForm(_('Nickname not allowed.')); - return; - } - - if (User::staticGet('nickname', $nickname)) { - $this->showForm(_('Nickname already in use. Try another one.')); - return; - } - - list($display, $canonical, $sreg) = $this->getSavedValues(); - - if (!$display || !$canonical) { - $this->serverError(_('Stored OpenID not found.')); - return; - } - - # Possible race condition... let's be paranoid - - $other = oid_get_user($canonical); - - if ($other) { - $this->serverError(_('Creating new account for OpenID that already has a user.')); - return; - } - - $location = ''; - if (!empty($sreg['country'])) { - if ($sreg['postcode']) { - # XXX: use postcode to get city and region - # XXX: also, store postcode somewhere -- it's valuable! - $location = $sreg['postcode'] . ', ' . $sreg['country']; - } else { - $location = $sreg['country']; - } - } - - if (!empty($sreg['fullname']) && mb_strlen($sreg['fullname']) <= 255) { - $fullname = $sreg['fullname']; - } else { - $fullname = ''; - } - - if (!empty($sreg['email']) && Validate::email($sreg['email'], true)) { - $email = $sreg['email']; - } else { - $email = ''; - } - - # XXX: add language - # XXX: add timezone - - $args = array('nickname' => $nickname, - 'email' => $email, - 'fullname' => $fullname, - 'location' => $location); - - if (!empty($invite)) { - $args['code'] = $invite->code; - } - - $user = User::register($args); - - $result = oid_link_user($user->id, $canonical, $display); - - oid_set_last($display); - common_set_user($user); - common_real_login(true); - if (isset($_SESSION['openid_rememberme']) && $_SESSION['openid_rememberme']) { - common_rememberme($user); - } - unset($_SESSION['openid_rememberme']); - common_redirect(common_local_url('showstream', array('nickname' => $user->nickname)), - 303); - } - - function connectUser() - { - $nickname = $this->trimmed('nickname'); - $password = $this->trimmed('password'); - - if (!common_check_user($nickname, $password)) { - $this->showForm(_('Invalid username or password.')); - return; - } - - # They're legit! - - $user = User::staticGet('nickname', $nickname); - - list($display, $canonical, $sreg) = $this->getSavedValues(); - - if (!$display || !$canonical) { - $this->serverError(_('Stored OpenID not found.')); - return; - } - - $result = oid_link_user($user->id, $canonical, $display); - - if (!$result) { - $this->serverError(_('Error connecting user to OpenID.')); - return; - } - - oid_update_user($user, $sreg); - oid_set_last($display); - common_set_user($user); - common_real_login(true); - if (isset($_SESSION['openid_rememberme']) && $_SESSION['openid_rememberme']) { - common_rememberme($user); - } - unset($_SESSION['openid_rememberme']); - $this->goHome($user->nickname); - } - - function goHome($nickname) - { - $url = common_get_returnto(); - if ($url) { - # We don't have to return to it again - common_set_returnto(null); - } else { - $url = common_local_url('all', - array('nickname' => - $nickname)); - } - common_redirect($url, 303); - } - - function bestNewNickname($display, $sreg) - { - - # Try the passed-in nickname - - if (!empty($sreg['nickname'])) { - $nickname = $this->nicknamize($sreg['nickname']); - if ($this->isNewNickname($nickname)) { - return $nickname; - } - } - - # Try the full name - - if (!empty($sreg['fullname'])) { - $fullname = $this->nicknamize($sreg['fullname']); - if ($this->isNewNickname($fullname)) { - return $fullname; - } - } - - # Try the URL - - $from_url = $this->openidToNickname($display); - - if ($from_url && $this->isNewNickname($from_url)) { - return $from_url; - } - - # XXX: others? - - return null; - } - - function isNewNickname($str) - { - if (!Validate::string($str, array('min_length' => 1, - 'max_length' => 64, - 'format' => NICKNAME_FMT))) { - return false; - } - if (!User::allowed_nickname($str)) { - return false; - } - if (User::staticGet('nickname', $str)) { - return false; - } - return true; - } - - function openidToNickname($openid) - { - if (Auth_Yadis_identifierScheme($openid) == 'XRI') { - return $this->xriToNickname($openid); - } else { - return $this->urlToNickname($openid); - } - } - - # We try to use an OpenID URL as a legal StatusNet user name in this order - # 1. Plain hostname, like http://evanp.myopenid.com/ - # 2. One element in path, like http://profile.typekey.com/EvanProdromou/ - # or http://getopenid.com/evanprodromou - - function urlToNickname($openid) - { - static $bad = array('query', 'user', 'password', 'port', 'fragment'); - - $parts = parse_url($openid); - - # If any of these parts exist, this won't work - - foreach ($bad as $badpart) { - if (array_key_exists($badpart, $parts)) { - return null; - } - } - - # We just have host and/or path - - # If it's just a host... - if (array_key_exists('host', $parts) && - (!array_key_exists('path', $parts) || strcmp($parts['path'], '/') == 0)) - { - $hostparts = explode('.', $parts['host']); - - # Try to catch common idiom of nickname.service.tld - - if ((count($hostparts) > 2) && - (strlen($hostparts[count($hostparts) - 2]) > 3) && # try to skip .co.uk, .com.au - (strcmp($hostparts[0], 'www') != 0)) - { - return $this->nicknamize($hostparts[0]); - } else { - # Do the whole hostname - return $this->nicknamize($parts['host']); - } - } else { - if (array_key_exists('path', $parts)) { - # Strip starting, ending slashes - $path = preg_replace('@/$@', '', $parts['path']); - $path = preg_replace('@^/@', '', $path); - if (strpos($path, '/') === false) { - return $this->nicknamize($path); - } - } - } - - return null; - } - - function xriToNickname($xri) - { - $base = $this->xriBase($xri); - - if (!$base) { - return null; - } else { - # =evan.prodromou - # or @gratis*evan.prodromou - $parts = explode('*', substr($base, 1)); - return $this->nicknamize(array_pop($parts)); - } - } - - function xriBase($xri) - { - if (substr($xri, 0, 6) == 'xri://') { - return substr($xri, 6); - } else { - return $xri; - } - } - - # Given a string, try to make it work as a nickname - - function nicknamize($str) - { - $str = preg_replace('/\W/', '', $str); - return strtolower($str); - } -} diff --git a/actions/finishremotesubscribe.php b/actions/finishremotesubscribe.php index 871bc3d2d..b1cec66f4 100644 --- a/actions/finishremotesubscribe.php +++ b/actions/finishremotesubscribe.php @@ -1,5 +1,16 @@ <?php -/* +/** + * Handler for remote subscription finish callback + * + * PHP version 5 + * + * @category Action + * @package StatusNet + * @author Evan Prodromou <evan@status.net> + * @author Robin Millette <millette@status.net> + * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 + * @link http://status.net/ + * * StatusNet - the distributed open-source microblogging tool * Copyright (C) 2008, 2009, StatusNet, Inc. * @@ -15,285 +26,121 @@ * * 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/>. - */ + **/ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } -require_once(INSTALLDIR.'/lib/omb.php'); +require_once INSTALLDIR.'/extlib/libomb/service_consumer.php'; +require_once INSTALLDIR.'/lib/omb.php'; +/** + * Handler for remote subscription finish callback + * + * When a remote user subscribes a local user, a redirect to this action is + * issued after the remote user authorized his service to subscribe. + * + * @category Action + * @package Laconica + * @author Evan Prodromou <evan@status.net> + * @author Robin Millette <millette@controlyourself.ca> + * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 + * @link http://laconi.ca/ + */ class FinishremotesubscribeAction extends Action { + /** + * Class handler. + * + * @param array $args query arguments + * + * @return nothing + * + **/ function handle($args) { - parent::handle($args); - if (common_logged_in()) { - $this->clientError(_('You can use the local subscription!')); - return; - } - - $omb = $_SESSION['oauth_authorization_request']; + /* Restore session data. RemotesubscribeAction should have stored + this entry. */ + $service = unserialize($_SESSION['oauth_authorization_request']); - if (!$omb) { + if (!$service) { $this->clientError(_('Not expecting this response!')); return; } - common_debug('stored request: '.print_r($omb,true), __FILE__); - - common_remove_magic_from_request(); - $req = OAuthRequest::from_request('POST', common_local_url('finishuserauthorization')); - - $token = $req->get_parameter('oauth_token'); - - # I think this is the success metric - - if ($token != $omb['token']) { - $this->clientError(_('Not authorized.')); - return; - } - - $version = $req->get_parameter('omb_version'); - - if ($version != OMB_VERSION_01) { - $this->clientError(_('Unknown version of OMB protocol.')); - return; - } - - $nickname = $req->get_parameter('omb_listener_nickname'); - - if (!$nickname) { - $this->clientError(_('No nickname provided by remote server.')); - return; - } - - $profile_url = $req->get_parameter('omb_listener_profile'); + common_debug('stored request: '. print_r($service, true), __FILE__); - if (!$profile_url) { - $this->clientError(_('No profile URL returned by server.')); - return; - } - - if (!Validate::uri($profile_url, array('allowed_schemes' => array('http', 'https')))) { - $this->clientError(_('Invalid profile URL returned by server.')); - return; - } - - if ($profile_url == common_local_url('showstream', array('nickname' => $nickname))) { - $this->clientError(_('You can use the local subscription!')); - return; - } - - common_debug('listenee: "'.$omb['listenee'].'"', __FILE__); - - $user = User::staticGet('nickname', $omb['listenee']); + /* Create user objects for both users. Do it early for request + validation. */ + $user = User::staticGet('uri', $service->getListeneeURI()); if (!$user) { - $this->clientError(_('User being listened to doesn\'t exist.')); + $this->clientError(_('User being listened to does not exist.')); return; } - $other = User::staticGet('uri', $omb['listener']); + $other = User::staticGet('uri', $service->getListenerURI()); if ($other) { $this->clientError(_('You can use the local subscription!')); return; } - $fullname = $req->get_parameter('omb_listener_fullname'); - $homepage = $req->get_parameter('omb_listener_homepage'); - $bio = $req->get_parameter('omb_listener_bio'); - $location = $req->get_parameter('omb_listener_location'); - $avatar_url = $req->get_parameter('omb_listener_avatar'); + $remote = Remote_profile::staticGet('uri', $service->getListenerURI()); - list($newtok, $newsecret) = $this->access_token($omb); + $profile = Profile::staticGet($remote->id); - if (!$newtok || !$newsecret) { - $this->clientError(_('Couldn\'t convert request tokens to access tokens.')); + if ($user->hasBlocked($profile)) { + $this->clientError(_('That user has blocked you from subscribing.')); return; } - # XXX: possible attack point; subscribe and return someone else's profile URI - - $remote = Remote_profile::staticGet('uri', $omb['listener']); - - if ($remote) { - $exists = true; - $profile = Profile::staticGet($remote->id); - $orig_remote = clone($remote); - $orig_profile = clone($profile); - # XXX: compare current postNotice and updateProfile URLs to the ones - # stored in the DB to avoid (possibly...) above attack - } else { - $exists = false; - $remote = new Remote_profile(); - $remote->uri = $omb['listener']; - $profile = new Profile(); - } - - $profile->nickname = $nickname; - $profile->profileurl = $profile_url; - - if (!is_null($fullname)) { - $profile->fullname = $fullname; - } - if (!is_null($homepage)) { - $profile->homepage = $homepage; - } - if (!is_null($bio)) { - $profile->bio = $bio; - } - if (!is_null($location)) { - $profile->location = $location; - } - - if ($exists) { - $profile->update($orig_profile); - } else { - $profile->created = DB_DataObject_Cast::dateTime(); # current time - $id = $profile->insert(); - if (!$id) { - $this->serverError(_('Error inserting new profile')); + /* Perform the handling itself via libomb. */ + try { + $service->finishAuthorization(); + } catch (OAuthException $e) { + if ($e->getMessage() == 'The authorized token does not equal the ' . + 'submitted token.') { + $this->clientError(_('You are not authorized.')); return; - } - $remote->id = $id; - } - - if ($avatar_url) { - if (!$this->add_avatar($profile, $avatar_url)) { - $this->serverError(_('Error inserting avatar')); - return; - } - } - - $remote->postnoticeurl = $omb['post_notice_url']; - $remote->updateprofileurl = $omb['update_profile_url']; - - if ($exists) { - if (!$remote->update($orig_remote)) { - $this->serverError(_('Error updating remote profile')); + } else { + $this->clientError(_('Could not convert request token to ' . + 'access token.')); return; } - } else { - $remote->created = DB_DataObject_Cast::dateTime(); # current time - if (!$remote->insert()) { - $this->serverError(_('Error inserting remote profile')); - return; - } - } - - if ($user->hasBlocked($profile)) { - $this->clientError(_('That user has blocked you from subscribing.')); + } catch (OMB_RemoteServiceException $e) { + $this->clientError(_('Remote service uses unknown version of ' . + 'OMB protocol.')); + return; + } catch (Exception $e) { + common_debug('Got exception ' . print_r($e, true), __FILE__); + $this->clientError($e->getMessage()); return; } - $sub = new Subscription(); - - $sub->subscriber = $remote->id; - $sub->subscribed = $user->id; - - $sub_exists = false; - - if ($sub->find(true)) { - $sub_exists = true; - $orig_sub = clone($sub); - } else { - $sub_exists = false; - $sub->created = DB_DataObject_Cast::dateTime(); # current time - } - - $sub->token = $newtok; - $sub->secret = $newsecret; + /* The service URLs are not accessible from datastore, so setting them + after insertion of the profile. */ + $orig_remote = clone($remote); - if ($sub_exists) { - $result = $sub->update($orig_sub); - } else { - $result = $sub->insert(); - } + $remote->postnoticeurl = + $service->getServiceURI(OMB_ENDPOINT_POSTNOTICE); + $remote->updateprofileurl = + $service->getServiceURI(OMB_ENDPOINT_UPDATEPROFILE); - if (!$result) { - common_log_db_error($sub, ($sub_exists) ? 'UPDATE' : 'INSERT', __FILE__); - $this->clientError(_('Couldn\'t insert new subscription.')); - return; + if (!$remote->update($orig_remote)) { + $this->serverError(_('Error updating remote profile')); + return; } - # Notify user, if necessary - - mail_subscribe_notify_profile($user, $profile); - - # Clear the data + /* Clear the session data. */ unset($_SESSION['oauth_authorization_request']); - # If we show subscriptions in reverse chron order, this should - # show up close to the top of the page - + /* If we show subscriptions in reverse chronological order, the new one + should show up close to the top of the page. */ common_redirect(common_local_url('subscribers', array('nickname' => $user->nickname)), 303); } - - function add_avatar($profile, $url) - { - $temp_filename = tempnam(sys_get_temp_dir(), 'listener_avatar'); - copy($url, $temp_filename); - $imagefile = new ImageFile($profile->id, $temp_filename); - $filename = Avatar::filename($profile->id, - image_type_to_extension($imagefile->type), - null, - common_timestamp()); - rename($temp_filename, Avatar::path($filename)); - return $profile->setOriginal($filename); - } - - function access_token($omb) - { - - common_debug('starting request for access token', __FILE__); - - $con = omb_oauth_consumer(); - $tok = new OAuthToken($omb['token'], $omb['secret']); - - common_debug('using request token "'.$tok.'"', __FILE__); - - $url = $omb['access_token_url']; - - common_debug('using access token url "'.$url.'"', __FILE__); - - # XXX: Is this the right thing to do? Strip off GET params and make them - # POST params? Seems wrong to me. - - $parsed = parse_url($url); - $params = array(); - parse_str($parsed['query'], $params); - - $req = OAuthRequest::from_consumer_and_token($con, $tok, "POST", $url, $params); - - $req->set_parameter('omb_version', OMB_VERSION_01); - - # XXX: test to see if endpoint accepts this signature method - - $req->sign_request(omb_hmac_sha1(), $con, $tok); - - # We re-use this tool's fetcher, since it's pretty good - - common_debug('posting to access token url "'.$req->get_normalized_http_url().'"', __FILE__); - common_debug('posting request data "'.$req->to_postdata().'"', __FILE__); - - $fetcher = Auth_Yadis_Yadis::getHTTPFetcher(); - $result = $fetcher->post($req->get_normalized_http_url(), - $req->to_postdata(), - array('User-Agent: StatusNet/' . STATUSNET_VERSION)); - - common_debug('got result: "'.print_r($result,true).'"', __FILE__); - - if ($result->status != 200) { - return null; - } - - parse_str($result->body, $return); - - return array($return['oauth_token'], $return['oauth_token_secret']); - } } diff --git a/actions/foafgroup.php b/actions/foafgroup.php new file mode 100644 index 000000000..f5fd7fe88 --- /dev/null +++ b/actions/foafgroup.php @@ -0,0 +1,173 @@ +<?php +/* + * StatusNet the distributed open-source microblogging tool + * Copyright (C) 2008, 2009, StatusNet, Inc. + * + * 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 Mail + * @package StatusNet + * @author Evan Prodromou <evan@status.net> + * @author Toby Inkster <mail@tobyinkster.co.uk> + * @copyright 2009 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } + +class FoafGroupAction extends Action +{ + function isReadOnly($args) + { + return true; + } + + function prepare($args) + { + parent::prepare($args); + + $nickname_arg = $this->arg('nickname'); + + if (empty($nickname_arg)) { + $this->clientError(_('No such group.'), 404); + return false; + } + + $this->nickname = common_canonical_nickname($nickname_arg); + + // Permanent redirect on non-canonical nickname + + if ($nickname_arg != $this->nickname) { + common_redirect(common_local_url('foafgroup', + array('nickname' => $this->nickname)), + 301); + return false; + } + + $this->group = User_group::staticGet('nickname', $this->nickname); + + if (!$this->group) { + $this->clientError(_('No such group.'), 404); + return false; + } + + common_set_returnto($this->selfUrl()); + + return true; + } + + function handle($args) + { + parent::handle($args); + + header('Content-Type: application/rdf+xml'); + + $this->startXML(); + $this->elementStart('rdf:RDF', array('xmlns:rdf' => + 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', + 'xmlns:dcterms' => + 'http://purl.org/dc/terms/', + 'xmlns:sioc' => + 'http://rdfs.org/sioc/ns#', + 'xmlns:foaf' => + 'http://xmlns.com/foaf/0.1/', + 'xmlns:statusnet' => + 'http://status.net/ont/', + 'xmlns' => 'http://xmlns.com/foaf/0.1/')); + + $this->showPpd(common_local_url('foafgroup', array('nickname' => $this->nickname)), $this->group->permalink()); + + $this->elementStart('Group', array('rdf:about' => + $this->group->permalink())); + if ($this->group->fullname) { + $this->element('name', null, $this->group->fullname); + } + if ($this->group->description) { + $this->element('dcterms:description', null, $this->group->description); + } + if ($this->group->nickname) { + $this->element('dcterms:identifier', null, $this->group->nickname); + $this->element('nick', null, $this->group->nickname); + } + foreach ($this->group->getAliases() as $alias) { + $this->element('nick', null, $alias); + } + if ($this->group->homeUrl()) { + $this->element('weblog', array('rdf:resource' => $this->group->homeUrl())); + } + if ($this->group->homepage) { + $this->element('page', array('rdf:resource' => $this->group->homepage)); + } + if ($this->group->homepage_logo) { + $this->element('depiction', array('rdf:resource' => $this->group->homepage_logo)); + } + + $members = $this->group->getMembers(); + $member_details = array(); + while ($members->fetch()) { + $member_uri = common_local_url('userbyid', array('id'=>$members->id)); + $member_details[$member_uri] = array( + 'nickname' => $members->nickname + ); + $this->element('member', array('rdf:resource' => $member_uri)); + } + + $admins = $this->group->getAdmins(); + while ($admins->fetch()) { + $admin_uri = common_local_url('userbyid', array('id'=>$admins->id)); + $member_details[$admin_uri]['is_admin'] = true; + $this->element('statusnet:groupAdmin', array('rdf:resource' => $admin_uri)); + } + + $this->elementEnd('Group'); + + ksort($member_details); + foreach ($member_details as $uri => $details) { + if ($details['is_admin']) + { + $this->elementStart('Agent', array('rdf:about' => $uri)); + $this->element('nick', null, $details['nickname']); + $this->elementStart('holdsAccount'); + $this->elementStart('sioc:User', array('rdf:about'=>$uri.'#acct')); + $this->elementStart('sioc:has_function'); + $this->elementStart('statusnet:GroupAdminRole'); + $this->element('sioc:scope', array('rdf:resource' => $this->group->permalink())); + $this->elementEnd('statusnet:GroupAdminRole'); + $this->elementEnd('sioc:has_function'); + $this->elementEnd('sioc:User'); + $this->elementEnd('holdsAccount'); + $this->elementEnd('Agent'); + } + else + { + $this->element('Agent', array( + 'foaf:nick' => $details['nickname'], + 'rdf:about' => $uri, + )); + } + } + + $this->elementEnd('rdf:RDF'); + $this->endXML(); + } + + function showPpd($foaf_url, $person_uri) + { + $this->elementStart('Document', array('rdf:about' => $foaf_url)); + $this->element('primaryTopic', array('rdf:resource' => $person_uri)); + $this->elementEnd('Document'); + } + +}
\ No newline at end of file diff --git a/actions/grouprss.php b/actions/grouprss.php index 70c1ded48..6a6b55e78 100644 --- a/actions/grouprss.php +++ b/actions/grouprss.php @@ -104,6 +104,7 @@ class groupRssAction extends Rss10Action return false; } + $this->notices = $this->getNotices($this->limit); return true; } diff --git a/actions/groupsearch.php b/actions/groupsearch.php index 517f12789..55f4cee62 100644 --- a/actions/groupsearch.php +++ b/actions/groupsearch.php @@ -82,8 +82,7 @@ class GroupsearchAction extends SearchAction $message = _('If you can\'t find the group you\'re looking for, you can [create it](%%action.newgroup%%) yourself.'); } else { - $message = sprintf(_('Why not [register an account](%%%%action.%s%%%%) and [create the group](%%%%action.newgroup%%%%) yourself!'), - (!common_config('site','openidonly')) ? 'register' : 'openidlogin'); + $message = _('Why not [register an account](%%action.register%%) and [create the group](%%action.newgroup%%) yourself!'); } $this->elementStart('div', 'guide'); $this->raw(common_markup_to_html($message)); diff --git a/actions/invite.php b/actions/invite.php index 9fa6a76f6..788130c58 100644 --- a/actions/invite.php +++ b/actions/invite.php @@ -241,7 +241,7 @@ class InviteAction extends CurrentUserDesignAction common_root_url(), $personal, common_local_url('showstream', array('nickname' => $user->nickname)), - common_local_url((!common_config('site', 'openidonly')) ? 'register' : 'openidlogin', array('code' => $invite->code))); + common_local_url('register', array('code' => $invite->code))); mail_send($recipients, $headers, $body); } diff --git a/actions/login.php b/actions/login.php index ac8c40c3e..f6d016310 100644 --- a/actions/login.php +++ b/actions/login.php @@ -67,8 +67,6 @@ class LoginAction extends Action * * Switches on request method; either shows the form or handles its input. * - * Checks if only OpenID is allowed and redirects to openidlogin if so. - * * @param array $args $_REQUEST data * * @return void @@ -77,9 +75,7 @@ class LoginAction extends Action function handle($args) { parent::handle($args); - if (common_config('site', 'openidonly')) { - common_redirect(common_local_url('openidlogin')); - } else if (common_is_real_login()) { + if (common_is_real_login()) { $this->clientError(_('Already logged in.')); } else if ($_SERVER['REQUEST_METHOD'] == 'POST') { $this->checkLogin(); @@ -259,11 +255,6 @@ class LoginAction extends Action return _('For security reasons, please re-enter your ' . 'user name and password ' . 'before changing your settings.'); - } else if (common_config('openid', 'enabled')) { - return _('Login with your username and password. ' . - 'Don\'t have a username yet? ' . - '[Register](%%action.register%%) a new account, or ' . - 'try [OpenID](%%action.openidlogin%%). '); } else { return _('Login with your username and password. ' . 'Don\'t have a username yet? ' . diff --git a/actions/logout.php b/actions/logout.php index 298b2a484..1e0adae57 100644 --- a/actions/logout.php +++ b/actions/logout.php @@ -32,8 +32,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } -require_once INSTALLDIR.'/lib/openid.php'; - /** * Logout action class. * diff --git a/actions/newgroup.php b/actions/newgroup.php index 01cb636aa..a2cf72528 100644 --- a/actions/newgroup.php +++ b/actions/newgroup.php @@ -146,8 +146,8 @@ class NewgroupAction extends Action } else if (!is_null($fullname) && mb_strlen($fullname) > 255) { $this->showForm(_('Full name is too long (max 255 chars).')); return; - } else if (!is_null($description) && mb_strlen($description) > 140) { - $this->showForm(_('description is too long (max 140 chars).')); + } else if (User_group::descriptionTooLong($description)) { + $this->showForm(sprintf(_('description is too long (max %d chars).'), User_group::maxDescription())); return; } else if (!is_null($location) && mb_strlen($location) > 255) { $this->showForm(_('Location is too long (max 255 chars).')); diff --git a/actions/newmessage.php b/actions/newmessage.php index 828a339cf..a0b17fc18 100644 --- a/actions/newmessage.php +++ b/actions/newmessage.php @@ -144,9 +144,10 @@ class NewmessageAction extends Action } else { $content_shortened = common_shorten_links($this->content); - if (mb_strlen($content_shortened) > 140) { - $this->showForm(_('That\'s too long. ' . - 'Max message size is 140 chars.')); + if (Message::contentTooLong($content_shortened)) { + $this->showForm(sprintf(_('That\'s too long. ' . + 'Max message size is %d chars.'), + Message::maxContent())); return; } } diff --git a/actions/newnotice.php b/actions/newnotice.php index 6e3720e09..d5b0332f4 100644 --- a/actions/newnotice.php +++ b/actions/newnotice.php @@ -162,9 +162,10 @@ class NewnoticeAction extends Action $this->clientError(_('No content!')); } else { $content_shortened = common_shorten_links($content); - if (mb_strlen($content_shortened) > 140) { - $this->clientError(_('That\'s too long. '. - 'Max notice size is 140 chars.')); + if (Notice::contentTooLong($content_shortened)) { + $this->clientError(sprintf(_('That\'s too long. '. + 'Max notice size is %d chars.'), + Notice::maxContent())); } } @@ -241,9 +242,10 @@ class NewnoticeAction extends Action $short_fileurl = common_shorten_url($fileurl); $content_shortened .= ' ' . $short_fileurl; - if (mb_strlen($content_shortened) > 140) { + if (Notice::contentTooLong($content_shortened)) { $this->deleteFile($filename); - $this->clientError(_('Max notice size is 140 chars, including attachment URL.')); + $this->clientError(sprintf(_('Max notice size is %d chars, including attachment URL.'), + Notice::maxContent())); } // Also, not sure this is necessary -- Zach @@ -253,13 +255,6 @@ class NewnoticeAction extends Action $notice = Notice::saveNew($user->id, $content_shortened, 'web', 1, ($replyto == 'false') ? null : $replyto); - if (is_string($notice)) { - if (isset($filename)) { - $this->deleteFile($filename); - } - $this->clientError($notice); - } - if (isset($mimetype)) { $this->attachFile($notice, $fileRecord); } diff --git a/actions/noticesearch.php b/actions/noticesearch.php index 69dcd1a46..79cf572cc 100644 --- a/actions/noticesearch.php +++ b/actions/noticesearch.php @@ -121,9 +121,7 @@ class NoticesearchAction extends SearchAction $message = sprintf(_('Be the first to [post on this topic](%%%%action.newnotice%%%%?status_textarea=%s)!'), urlencode($q)); } else { - $message = sprintf(_('Why not [register an account](%%%%action.%s%%%%) and be the first to [post on this topic](%%%%action.newnotice%%%%?status_textarea=%s)!'), - (!common_config('site','openidonly')) ? 'register' : 'openidlogin', - urlencode($q)); + $message = sprintf(_('Why not [register an account](%%%%action.register%%%%) and be the first to [post on this topic](%%%%action.newnotice%%%%?status_textarea=%s)!'), urlencode($q)); } $this->elementStart('div', 'guide'); diff --git a/actions/openidlogin.php b/actions/openidlogin.php deleted file mode 100644 index 9b7deefb6..000000000 --- a/actions/openidlogin.php +++ /dev/null @@ -1,139 +0,0 @@ -<?php -/* - * StatusNet - the distributed open-source microblogging tool - * Copyright (C) 2008, 2009, StatusNet, Inc. - * - * 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/>. - */ - -if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } - -require_once(INSTALLDIR.'/lib/openid.php'); - -class OpenidloginAction extends Action -{ - function handle($args) - { - parent::handle($args); - if (!common_config('openid', 'enabled')) { - common_redirect(common_local_url('login')); - } else if (common_is_real_login()) { - $this->clientError(_('Already logged in.')); - } else if ($_SERVER['REQUEST_METHOD'] == 'POST') { - $openid_url = $this->trimmed('openid_url'); - - # CSRF protection - $token = $this->trimmed('token'); - if (!$token || $token != common_session_token()) { - $this->showForm(_('There was a problem with your session token. Try again, please.'), $openid_url); - return; - } - - $rememberme = $this->boolean('rememberme'); - - common_ensure_session(); - - $_SESSION['openid_rememberme'] = $rememberme; - - $result = oid_authenticate($openid_url, - 'finishopenidlogin'); - - if (is_string($result)) { # error message - unset($_SESSION['openid_rememberme']); - $this->showForm($result, $openid_url); - } - } else { - $openid_url = oid_get_last(); - $this->showForm(null, $openid_url); - } - } - - function getInstructions() - { - if (common_logged_in() && !common_is_real_login() && - common_get_returnto()) { - // rememberme logins have to reauthenticate before - // changing any profile settings (cookie-stealing protection) - return _('For security reasons, please re-login with your ' . - '[OpenID](%%doc.openid%%) ' . - 'before changing your settings.'); - } else { - return _('Login with an [OpenID](%%doc.openid%%) account.'); - } - } - - function showPageNotice() - { - if ($this->error) { - $this->element('div', array('class' => 'error'), $this->error); - } else { - $instr = $this->getInstructions(); - $output = common_markup_to_html($instr); - $this->elementStart('div', 'instructions'); - $this->raw($output); - $this->elementEnd('div'); - } - } - - function showScripts() - { - parent::showScripts(); - $this->autofocus('openid_url'); - } - - function title() - { - return _('OpenID Login'); - } - - function showForm($error=null, $openid_url) - { - $this->error = $error; - $this->openid_url = $openid_url; - $this->showPage(); - } - - function showContent() { - $formaction = common_local_url('openidlogin'); - $this->elementStart('form', array('method' => 'post', - 'id' => 'form_openid_login', - 'class' => 'form_settings', - 'action' => $formaction)); - $this->elementStart('fieldset'); - $this->element('legend', null, _('OpenID login')); - $this->hidden('token', common_session_token()); - - $this->elementStart('ul', 'form_data'); - $this->elementStart('li'); - $this->input('openid_url', _('OpenID URL'), - $this->openid_url, - _('Your OpenID URL')); - $this->elementEnd('li'); - $this->elementStart('li', array('id' => 'settings_rememberme')); - $this->checkbox('rememberme', _('Remember me'), false, - _('Automatically login in the future; ' . - 'not for shared computers!')); - $this->elementEnd('li'); - $this->elementEnd('ul'); - $this->submit('submit', _('Login')); - $this->elementEnd('fieldset'); - $this->elementEnd('form'); - } - - function showLocalNav() - { - $nav = new LoginGroupNav($this); - $nav->show(); - } -} diff --git a/actions/openidsettings.php b/actions/openidsettings.php deleted file mode 100644 index 30725fc1b..000000000 --- a/actions/openidsettings.php +++ /dev/null @@ -1,246 +0,0 @@ -<?php -/** - * StatusNet, the distributed open-source microblogging tool - * - * Settings for OpenID - * - * 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 Settings - * @package StatusNet - * @author Evan Prodromou <evan@status.net> - * @copyright 2008-2009 StatusNet, Inc. - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://status.net/ - */ - -if (!defined('STATUSNET') && !defined('LACONICA')) { - exit(1); -} - -require_once INSTALLDIR.'/lib/accountsettingsaction.php'; -require_once INSTALLDIR.'/lib/openid.php'; - -/** - * Settings for OpenID - * - * Lets users add, edit and delete OpenIDs from their account - * - * @category Settings - * @package StatusNet - * @author Evan Prodromou <evan@status.net> - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://status.net/ - */ - -class OpenidsettingsAction extends AccountSettingsAction -{ - /** - * Title of the page - * - * @return string Page title - */ - - function title() - { - return _('OpenID settings'); - } - - /** - * Instructions for use - * - * @return string Instructions for use - */ - - function getInstructions() - { - return _('[OpenID](%%doc.openid%%) lets you log into many sites' . - ' with the same user account.'. - ' Manage your associated OpenIDs from here.'); - } - - function showScripts() - { - parent::showScripts(); - $this->autofocus('openid_url'); - } - - /** - * Show the form for OpenID management - * - * We have one form with a few different submit buttons to do different things. - * - * @return void - */ - - function showContent() - { - if (!common_config('openid', 'enabled')) { - $this->element('div', array('class' => 'error'), - _('OpenID is not available.')); - return; - } - - $user = common_current_user(); - - $this->elementStart('form', array('method' => 'post', - 'id' => 'form_settings_openid_add', - 'class' => 'form_settings', - 'action' => - common_local_url('openidsettings'))); - $this->elementStart('fieldset', array('id' => 'settings_openid_add')); - $this->element('legend', null, _('Add OpenID')); - $this->hidden('token', common_session_token()); - $this->element('p', 'form_guide', - _('If you want to add an OpenID to your account, ' . - 'enter it in the box below and click "Add".')); - $this->elementStart('ul', 'form_data'); - $this->elementStart('li'); - $this->element('label', array('for' => 'openid_url'), - _('OpenID URL')); - $this->element('input', array('name' => 'openid_url', - 'type' => 'text', - 'id' => 'openid_url')); - $this->elementEnd('li'); - $this->elementEnd('ul'); - $this->element('input', array('type' => 'submit', - 'id' => 'settings_openid_add_action-submit', - 'name' => 'add', - 'class' => 'submit', - 'value' => _('Add'))); - $this->elementEnd('fieldset'); - $this->elementEnd('form'); - - $oid = new User_openid(); - - $oid->user_id = $user->id; - - $cnt = $oid->find(); - - if ($cnt > 0) { - - $this->element('h2', null, _('Remove OpenID')); - - if ($cnt == 1 && !$user->password) { - - $this->element('p', 'form_guide', - _('Removing your only OpenID '. - 'would make it impossible to log in! ' . - 'If you need to remove it, '. - 'add another OpenID first.')); - - if ($oid->fetch()) { - $this->elementStart('p'); - $this->element('a', array('href' => $oid->canonical), - $oid->display); - $this->elementEnd('p'); - } - - } else { - - $this->element('p', 'form_guide', - _('You can remove an OpenID from your account '. - 'by clicking the button marked "Remove".')); - $idx = 0; - - while ($oid->fetch()) { - $this->elementStart('form', - array('method' => 'POST', - 'id' => 'form_settings_openid_delete' . $idx, - 'class' => 'form_settings', - 'action' => - common_local_url('openidsettings'))); - $this->elementStart('fieldset'); - $this->hidden('token', common_session_token()); - $this->element('a', array('href' => $oid->canonical), - $oid->display); - $this->element('input', array('type' => 'hidden', - 'id' => 'openid_url'.$idx, - 'name' => 'openid_url', - 'value' => $oid->canonical)); - $this->element('input', array('type' => 'submit', - 'id' => 'remove'.$idx, - 'name' => 'remove', - 'class' => 'submit remove', - 'value' => _('Remove'))); - $this->elementEnd('fieldset'); - $this->elementEnd('form'); - $idx++; - } - } - } - } - - /** - * Handle a POST request - * - * Muxes to different sub-functions based on which button was pushed - * - * @return void - */ - - function handlePost() - { - // CSRF protection - $token = $this->trimmed('token'); - if (!$token || $token != common_session_token()) { - $this->showForm(_('There was a problem with your session token. '. - 'Try again, please.')); - return; - } - - if ($this->arg('add')) { - $result = oid_authenticate($this->trimmed('openid_url'), - 'finishaddopenid'); - if (is_string($result)) { // error message - $this->showForm($result); - } - } else if ($this->arg('remove')) { - $this->removeOpenid(); - } else { - $this->showForm(_('Something weird happened.')); - } - } - - /** - * Handles a request to remove an OpenID from the user's account - * - * Validates input and, if everything is OK, deletes the OpenID. - * Reloads the form with a success or error notification. - * - * @return void - */ - - function removeOpenid() - { - $openid_url = $this->trimmed('openid_url'); - - $oid = User_openid::staticGet('canonical', $openid_url); - - if (!$oid) { - $this->showForm(_('No such OpenID.')); - return; - } - $cur = common_current_user(); - if (!$cur || $oid->user_id != $cur->id) { - $this->showForm(_('That OpenID does not belong to you.')); - return; - } - $oid->delete(); - $this->showForm(_('OpenID removed.'), true); - return; - } -} diff --git a/actions/othersettings.php b/actions/othersettings.php index f898e2207..011b4fc83 100644 --- a/actions/othersettings.php +++ b/actions/othersettings.php @@ -97,19 +97,20 @@ class OthersettingsAction extends AccountSettingsAction $this->elementStart('fieldset'); $this->hidden('token', common_session_token()); - // I18N - - $services = array( - '' => 'None', - 'ur1.ca' => 'ur1.ca (free service)', - '2tu.us' => '2tu.us (free service)', - 'ptiturl.com' => 'ptiturl.com', - 'bit.ly' => 'bit.ly', - 'tinyurl.com' => 'tinyurl.com', - 'is.gd' => 'is.gd', - 'snipr.com' => 'snipr.com', - 'metamark.net' => 'metamark.net' - ); + $services=array(); + global $_shorteners; + if($_shorteners){ + foreach($_shorteners as $name=>$value) + { + $services[$name]=$name; + if($value['info']['freeService']){ + // I18N + $services[$name].=' (free service)'; + } + } + } + asort($services); + $services['']='None'; $this->elementStart('ul', 'form_data'); $this->elementStart('li'); diff --git a/actions/postnotice.php b/actions/postnotice.php index e775ca17e..c2e1c44ca 100644 --- a/actions/postnotice.php +++ b/actions/postnotice.php @@ -1,5 +1,16 @@ <?php -/* +/** + * Handle postnotice action + * + * PHP version 5 + * + * @category Action + * @package StatusNet + * @author Evan Prodromou <evan@status.net> + * @author Robin Millette <millette@status.net> + * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 + * @link http://status.net/ + * * StatusNet - the distributed open-source microblogging tool * Copyright (C) 2008, 2009, StatusNet, Inc. * @@ -19,73 +30,67 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } -require_once(INSTALLDIR.'/lib/omb.php'); +require_once INSTALLDIR.'/lib/omb.php'; +require_once INSTALLDIR.'/extlib/libomb/service_provider.php'; +/** + * Handler for postnotice action + * + * @category Action + * @package StatusNet + * @author Evan Prodromou <evan@status.net> + * @author Robin Millette <millette@status.net> + * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 + * @link http://status.net/ + */ class PostnoticeAction extends Action { + /** + * For initializing members of the class. + * + * @param array $argarray misc. arguments + * + * @return boolean true + */ + function prepare($argarray) + { + parent::prepare($argarray); + try { + $this->checkNotice(); + } catch (Exception $e) { + $this->clientError($e->getMessage()); + return false; + } + return true; + } + function handle($args) { parent::handle($args); try { - common_remove_magic_from_request(); - $req = OAuthRequest::from_request('POST', common_local_url('postnotice')); - # Note: server-to-server function! - $server = omb_oauth_server(); - list($consumer, $token) = $server->verify_request($req); - if ($this->save_notice($req, $consumer, $token)) { - print "omb_version=".OMB_VERSION_01; - } - } catch (OAuthException $e) { + $srv = new OMB_Service_Provider(null, omb_oauth_datastore(), + omb_oauth_server()); + $srv->handlePostNotice(); + } catch (Exception $e) { $this->serverError($e->getMessage()); return; } } - function save_notice(&$req, &$consumer, &$token) + function checkNotice() { - $version = $req->get_parameter('omb_version'); - if ($version != OMB_VERSION_01) { - $this->clientError(_('Unsupported OMB version'), 400); - return false; - } - # First, check to see - $listenee = $req->get_parameter('omb_listenee'); - $remote_profile = Remote_profile::staticGet('uri', $listenee); - if (!$remote_profile) { - $this->clientError(_('Profile unknown'), 403); - return false; - } - $sub = Subscription::staticGet('token', $token->key); - if (!$sub) { - $this->clientError(_('No such subscription'), 403); - return false; - } - $content = $req->get_parameter('omb_notice_content'); - $content_shortened = common_shorten_links($content); - if (mb_strlen($content_shortened) > 140) { + $content = common_shorten_links($_POST['omb_notice_content']); + if (Notice::contentTooLong($content)) { $this->clientError(_('Invalid notice content'), 400); return false; } - $notice_uri = $req->get_parameter('omb_notice'); - if (!Validate::uri($notice_uri) && - !common_valid_tag($notice_uri)) { - $this->clientError(_('Invalid notice uri'), 400); - return false; - } - $notice_url = $req->get_parameter('omb_notice_url'); - if ($notice_url && !common_valid_http_url($notice_url)) { - $this->clientError(_('Invalid notice url'), 400); - return false; + $license = $_POST['omb_notice_license']; + $site_license = common_config('license', 'url'); + if ($license && !common_compatible_license($license, $site_license)) { + throw new Exception(sprintf(_('Notice license ‘%s’ is not ' . + 'compatible with site license ‘%s’.'), + $license, $site_license)); } - $notice = Notice::staticGet('uri', $notice_uri); - if (!$notice) { - $notice = Notice::saveNew($remote_profile->id, $content, 'omb', false, null, $notice_uri); - if (is_string($notice)) { - common_server_serror($notice, 500); - return false; - } - common_broadcast_notice($notice, true); - } - return true; } } +?>
\ No newline at end of file diff --git a/actions/profilesettings.php b/actions/profilesettings.php index 2d66e9946..5445d9bb2 100644 --- a/actions/profilesettings.php +++ b/actions/profilesettings.php @@ -117,9 +117,16 @@ class ProfilesettingsAction extends AccountSettingsAction _('URL of your homepage, blog, or profile on another site')); $this->elementEnd('li'); $this->elementStart('li'); + $maxBio = Profile::maxBio(); + if ($maxBio > 0) { + $bioInstr = sprintf(_('Describe yourself and your interests in %d chars'), + $maxBio); + } else { + $bioInstr = _('Describe yourself and your interests'); + } $this->textarea('bio', _('Bio'), ($this->arg('bio')) ? $this->arg('bio') : $profile->bio, - _('Describe yourself and your interests in 140 chars')); + $bioInstr); $this->elementEnd('li'); $this->elementStart('li'); $this->input('location', _('Location'), @@ -210,8 +217,9 @@ class ProfilesettingsAction extends AccountSettingsAction } else if (!is_null($fullname) && mb_strlen($fullname) > 255) { $this->showForm(_('Full name is too long (max 255 chars).')); return; - } else if (!is_null($bio) && mb_strlen($bio) > 140) { - $this->showForm(_('Bio is too long (max 140 chars).')); + } else if (Profile::bioTooLong($bio)) { + $this->showForm(sprintf(_('Bio is too long (max %d chars).'), + Profile::maxBio())); return; } else if (!is_null($location) && mb_strlen($location) > 255) { $this->showForm(_('Location is too long (max 255 chars).')); diff --git a/actions/public.php b/actions/public.php index d426648f3..73fad182a 100644 --- a/actions/public.php +++ b/actions/public.php @@ -114,8 +114,6 @@ class PublicAction extends Action { parent::handle($args); - header('X-XRDS-Location: '. common_local_url('publicxrds')); - $this->showPage(); } @@ -157,22 +155,6 @@ class PublicAction extends Action } /** - * Extra head elements - * - * We include a <meta> element linking to the publicxrds page, for OpenID - * client-side authentication. - * - * @return void - */ - - function extraHead() - { - // for client side of OpenID authentication - $this->element('meta', array('http-equiv' => 'X-XRDS-Location', - 'content' => common_local_url('publicxrds'))); - } - - /** * Show tabset for this page * * Uses the PublicGroupNav widget @@ -196,8 +178,7 @@ class PublicAction extends Action } else { if (! (common_config('site','closed') || common_config('site','inviteonly'))) { - $message .= sprintf(_('Why not [register an account](%%%%action.%s%%%%) and be the first to post!'), - (!common_config('site','openidonly')) ? 'register' : 'openidlogin'); + $message .= _('Why not [register an account](%%action.register%%) and be the first to post!'); } } @@ -244,11 +225,10 @@ class PublicAction extends Action function showAnonymousMessage() { if (! (common_config('site','closed') || common_config('site','inviteonly'))) { - $m = sprintf(_('This is %%%%site.name%%%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' . - 'based on the Free Software [StatusNet](http://status.net/) tool. ' . - '[Join now](%%%%action.%s%%%%) to share notices about yourself with friends, family, and colleagues! ' . - '([Read more](%%%%doc.help%%%%))'), - (!common_config('site','openidonly')) ? 'register' : 'openidlogin'); + $m = _('This is %%site.name%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' . + 'based on the Free Software [StatusNet](http://status.net/) tool. ' . + '[Join now](%%action.register%%) to share notices about yourself with friends, family, and colleagues! ' . + '([Read more](%%doc.help%%))'); } else { $m = _('This is %%site.name%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' . 'based on the Free Software [StatusNet](http://status.net/) tool.'); diff --git a/actions/publicrss.php b/actions/publicrss.php index 593888b9f..0c5d061cb 100644 --- a/actions/publicrss.php +++ b/actions/publicrss.php @@ -50,8 +50,22 @@ require_once INSTALLDIR.'/lib/rssaction.php'; class PublicrssAction extends Rss10Action { /** + * Read arguments and initialize members + * + * @param array $args Arguments from $_REQUEST + * @return boolean success + */ + + function prepare($args) + { + parent::prepare($args); + $this->notices = $this->getNotices($this->limit); + return true; + } + + /** * Initialization. - * + * * @return boolean true */ function init() @@ -73,7 +87,7 @@ class PublicrssAction extends Rss10Action while ($notice->fetch()) { $notices[] = clone($notice); } - + return $notices; } diff --git a/actions/publictagcloud.php b/actions/publictagcloud.php index 60bb53e27..e7f6ee36c 100644 --- a/actions/publictagcloud.php +++ b/actions/publictagcloud.php @@ -72,8 +72,7 @@ class PublictagcloudAction extends Action $message .= _('Be the first to post one!'); } else { - $message .= sprintf(_('Why not [register an account](%%%%action.%s%%%%) and be the first to post one!'), - (!common_config('site','openidonly')) ? 'register' : 'openidlogin'); + $message .= _('Why not [register an account](%%action.register%%) and be the first to post one!'); } $this->elementStart('div', 'guide'); diff --git a/actions/publicxrds.php b/actions/publicxrds.php deleted file mode 100644 index 209a10e3d..000000000 --- a/actions/publicxrds.php +++ /dev/null @@ -1,122 +0,0 @@ -<?php - -/** - * Public XRDS for OpenID - * - * PHP version 5 - * - * @category Action - * @package StatusNet - * @author Evan Prodromou <evan@status.net> - * @author Robin Millette <millette@status.net> - * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 - * @link http://status.net/ - * - * StatusNet - the distributed open-source microblogging tool - * Copyright (C) 2008, 2009, StatusNet, Inc. - * - * 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/>. - */ - -if (!defined('STATUSNET') && !defined('LACONICA')) { - exit(1); -} - -require_once INSTALLDIR.'/lib/openid.php'; - -/** - * Public XRDS for OpenID - * - * @category Action - * @package StatusNet - * @author Evan Prodromou <evan@status.net> - * @author Robin Millette <millette@status.net> - * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 - * @link http://status.net/ - * - * @todo factor out similarities with XrdsAction - */ -class PublicxrdsAction extends Action -{ - /** - * Is read only? - * - * @return boolean true - */ - function isReadOnly($args) - { - return true; - } - - /** - * Class handler. - * - * @param array $args array of arguments - * - * @return nothing - */ - function handle($args) - { - parent::handle($args); - header('Content-Type: application/xrds+xml'); - $this->startXML(); - $this->elementStart('XRDS', array('xmlns' => 'xri://$xrds')); - $this->elementStart('XRD', array('xmlns' => 'xri://$xrd*($v*2.0)', - 'xmlns:simple' => 'http://xrds-simple.net/core/1.0', - 'version' => '2.0')); - $this->element('Type', null, 'xri://$xrds*simple'); - foreach (array('finishopenidlogin', 'finishaddopenid') as $finish) { - $this->showService(Auth_OpenID_RP_RETURN_TO_URL_TYPE, - common_local_url($finish)); - } - $this->elementEnd('XRD'); - $this->elementEnd('XRDS'); - $this->endXML(); - } - - /** - * Show service. - * - * @param string $type XRDS type - * @param string $uri URI - * @param array $params type parameters, null by default - * @param array $sigs type signatures, null by default - * @param string $localId local ID, null by default - * - * @return void - */ - function showService($type, $uri, $params=null, $sigs=null, $localId=null) - { - $this->elementStart('Service'); - if ($uri) { - $this->element('URI', null, $uri); - } - $this->element('Type', null, $type); - if ($params) { - foreach ($params as $param) { - $this->element('Type', null, $param); - } - } - if ($sigs) { - foreach ($sigs as $sig) { - $this->element('Type', null, $sig); - } - } - if ($localId) { - $this->element('LocalID', null, $localId); - } - $this->elementEnd('Service'); - } -} - diff --git a/actions/register.php b/actions/register.php index eefbc340a..100ab7424 100644 --- a/actions/register.php +++ b/actions/register.php @@ -116,8 +116,6 @@ class RegisterAction extends Action * * Checks if registration is closed and shows an error if so. * - * Checks if only OpenID is allowed and redirects to openidlogin if so. - * * @param array $args $_REQUEST data * * @return void @@ -129,8 +127,6 @@ class RegisterAction extends Action if (common_config('site', 'closed')) { $this->clientError(_('Registration not allowed.')); - } else if (common_config('site', 'openidonly')) { - common_redirect(common_local_url('openidlogin')); } else if (common_logged_in()) { $this->clientError(_('Already logged in.')); } else if ($_SERVER['REQUEST_METHOD'] == 'POST') { @@ -217,8 +213,9 @@ class RegisterAction extends Action } else if (!is_null($fullname) && mb_strlen($fullname) > 255) { $this->showForm(_('Full name is too long (max 255 chars).')); return; - } else if (!is_null($bio) && mb_strlen($bio) > 140) { - $this->showForm(_('Bio is too long (max 140 chars).')); + } else if (Profile::bioTooLong($bio)) { + $this->showForm(sprintf(_('Bio is too long (max %d chars).'), + Profile::maxBio())); return; } else if (!is_null($location) && mb_strlen($location) > 255) { $this->showForm(_('Location is too long (max 255 chars).')); @@ -335,22 +332,11 @@ class RegisterAction extends Action } else if ($this->error) { $this->element('p', 'error', $this->error); } else { - if (common_config('openid', 'enabled')) { - $instr = - common_markup_to_html(_('With this form you can create '. - ' a new account. ' . - 'You can then post notices and '. - 'link up to friends and colleagues. '. - '(Have an [OpenID](http://openid.net/)? ' . - 'Try our [OpenID registration]'. - '(%%action.openidlogin%%)!)')); - } else { - $instr = - common_markup_to_html(_('With this form you can create '. - ' a new account. ' . - 'You can then post notices and '. - 'link up to friends and colleagues.')); - } + $instr = + common_markup_to_html(_('With this form you can create '. + ' a new account. ' . + 'You can then post notices and '. + 'link up to friends and colleagues. ')); $this->elementStart('div', 'instructions'); $this->raw($instr); @@ -463,10 +449,16 @@ class RegisterAction extends Action 'or profile on another site')); $this->elementEnd('li'); $this->elementStart('li'); + $maxBio = Profile::maxBio(); + if ($maxBio > 0) { + $bioInstr = sprintf(_('Describe yourself and your interests in %d chars'), + $maxBio); + } else { + $bioInstr = _('Describe yourself and your interests'); + } $this->textarea('bio', _('Bio'), $this->trimmed('bio'), - _('Describe yourself and your '. - 'interests in 140 chars')); + $bioInstr); $this->elementEnd('li'); $this->elementStart('li'); $this->input('location', _('Location'), diff --git a/actions/remotesubscribe.php b/actions/remotesubscribe.php index 374392d4a..aee2a5d8e 100644 --- a/actions/remotesubscribe.php +++ b/actions/remotesubscribe.php @@ -1,5 +1,16 @@ <?php -/* +/** + * Handler for remote subscription + * + * PHP version 5 + * + * @category Action + * @package StatusNet + * @author Evan Prodromou <evan@status.net> + * @author Robin Millette <millette@status.net> + * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 + * @link http://status.net/ + * * StatusNet - the distributed open-source microblogging tool * Copyright (C) 2008, 2009, StatusNet, Inc. * @@ -15,11 +26,24 @@ * * 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/>. - */ + **/ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } -require_once(INSTALLDIR.'/lib/omb.php'); +require_once INSTALLDIR.'/lib/omb.php'; +require_once INSTALLDIR.'/extlib/libomb/service_consumer.php'; +require_once INSTALLDIR.'/extlib/libomb/profile.php'; + +/** + * Handler for remote subscription + * + * @category Action + * @package StatusNet + * @author Evan Prodromou <evan@status.net> + * @author Robin Millette <millette@status.net> + * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 + * @link http://status.net/ + */ class RemotesubscribeAction extends Action { @@ -36,7 +60,7 @@ class RemotesubscribeAction extends Action return false; } - $this->nickname = $this->trimmed('nickname'); + $this->nickname = $this->trimmed('nickname'); $this->profile_url = $this->trimmed('profile_url'); return true; @@ -47,7 +71,7 @@ class RemotesubscribeAction extends Action parent::handle($args); if ($_SERVER['REQUEST_METHOD'] == 'POST') { - # CSRF protection + /* Use a session token for CSRF protection. */ $token = $this->trimmed('token'); if (!$token || $token != common_session_token()) { $this->showForm(_('There was a problem with your session token. '. @@ -71,13 +95,11 @@ class RemotesubscribeAction extends Action if ($this->err) { $this->element('div', 'error', $this->err); } else { - $inst = sprintf(_('To subscribe, you can [login](%%%%action.%s%%%%),' . - ' or [register](%%%%action.%s%%%%) a new ' . - ' account. If you already have an account ' . - ' on a [compatible microblogging site](%%doc.openmublog%%), ' . - ' enter your profile URL below.'), - (!common_config('site','openidonly')) ? 'login' : 'openidlogin', - (!common_config('site','openidonly')) ? 'register' : 'openidlogin'); + $inst = _('To subscribe, you can [login](%%action.login%%),' . + ' or [register](%%action.register%%) a new ' . + ' account. If you already have an account ' . + ' on a [compatible microblogging site](%%doc.openmublog%%), ' . + ' enter your profile URL below.'); $output = common_markup_to_html($inst); $this->elementStart('div', 'instructions'); $this->raw($output); @@ -92,8 +114,8 @@ class RemotesubscribeAction extends Action function showContent() { - # id = remotesubscribe conflicts with the - # button on profile page + /* The id 'remotesubscribe' conflicts with the + button on profile page. */ $this->elementStart('form', array('id' => 'form_remote_subscribe', 'method' => 'post', 'class' => 'form_settings', @@ -119,247 +141,50 @@ class RemotesubscribeAction extends Action function remoteSubscription() { - $user = $this->getUser(); - - if (!$user) { + if (!$this->nickname) { $this->showForm(_('No such user.')); return; } + $user = User::staticGet('nickname', $this->nickname); + $this->profile_url = $this->trimmed('profile_url'); if (!$this->profile_url) { - $this->showForm(_('No such user.')); + $this->showForm(_('No such user')); return; } - if (!Validate::uri($this->profile_url, array('allowed_schemes' => array('http', 'https')))) { + if (!common_valid_http_url($this->profile_url)) { $this->showForm(_('Invalid profile URL (bad format)')); return; } - $fetcher = Auth_Yadis_Yadis::getHTTPFetcher(); - $yadis = Auth_Yadis_Yadis::discover($this->profile_url, $fetcher); - - if (!$yadis || $yadis->failed) { - $this->showForm(_('Not a valid profile URL (no YADIS document).')); - return; - } - - # XXX: a little liberal for sites that accidentally put whitespace before the xml declaration - - $xrds =& Auth_Yadis_XRDS::parseXRDS(trim($yadis->response_text)); - - if (!$xrds) { - $this->showForm(_('Not a valid profile URL (no XRDS defined).')); - return; - } - - $omb = $this->getOmb($xrds); - - if (!$omb) { - $this->showForm(_('Not a valid profile URL (incorrect services).')); - return; - } - - if (omb_service_uri($omb[OAUTH_ENDPOINT_REQUEST]) == - common_local_url('requesttoken')) - { - $this->showForm(_('That\'s a local profile! Login to subscribe.')); + try { + $service = new OMB_Service_Consumer($this->profile_url, + common_root_url(), + omb_oauth_datastore()); + } catch (OMB_InvalidYadisException $e) { + $this->showForm(_('Not a valid profile URL (no YADIS document or ' . + 'no or invalid XRDS defined).')); return; } - if (User::staticGet('uri', omb_local_id($omb[OAUTH_ENDPOINT_REQUEST]))) { - $this->showForm(_('That\'s a local profile! Login to subscribe.')); + if ($service->getServiceURI(OAUTH_ENDPOINT_REQUEST) == + common_local_url('requesttoken') || + User::staticGet('uri', $service->getRemoteUserURI())) { + $this->showForm(_('That’s a local profile! Login to subscribe.')); return; } - list($token, $secret) = $this->requestToken($omb); - - if (!$token || !$secret) { - $this->showForm(_('Couldn\'t get a request token.')); + try { + $service->requestToken(); + } catch (OMB_RemoteServiceException $e) { + $this->showForm(_('Couldn’t get a request token.')); return; } - $this->requestAuthorization($user, $omb, $token, $secret); - } - - function getUser() - { - $user = null; - if ($this->nickname) { - $user = User::staticGet('nickname', $this->nickname); - } - return $user; - } - - function getOmb($xrds) - { - static $omb_endpoints = array(OMB_ENDPOINT_UPDATEPROFILE, OMB_ENDPOINT_POSTNOTICE); - static $oauth_endpoints = array(OAUTH_ENDPOINT_REQUEST, OAUTH_ENDPOINT_AUTHORIZE, - OAUTH_ENDPOINT_ACCESS); - $omb = array(); - - # XXX: the following code could probably be refactored to eliminate dupes - - $oauth_services = omb_get_services($xrds, OAUTH_DISCOVERY); - - if (!$oauth_services) { - return null; - } - - $oauth_service = $oauth_services[0]; - - $oauth_xrd = $this->getXRD($oauth_service, $xrds); - - if (!$oauth_xrd) { - return null; - } - - if (!$this->addServices($oauth_xrd, $oauth_endpoints, $omb)) { - return null; - } - - $omb_services = omb_get_services($xrds, OMB_NAMESPACE); - - if (!$omb_services) { - return null; - } - - $omb_service = $omb_services[0]; - - $omb_xrd = $this->getXRD($omb_service, $xrds); - - if (!$omb_xrd) { - return null; - } - - if (!$this->addServices($omb_xrd, $omb_endpoints, $omb)) { - return null; - } - - # XXX: check that we got all the services we needed - - foreach (array_merge($omb_endpoints, $oauth_endpoints) as $type) { - if (!array_key_exists($type, $omb) || !$omb[$type]) { - return null; - } - } - - if (!omb_local_id($omb[OAUTH_ENDPOINT_REQUEST])) { - return null; - } - - return $omb; - } - - function getXRD($main_service, $main_xrds) - { - $uri = omb_service_uri($main_service); - if (strpos($uri, "#") !== 0) { - # FIXME: more rigorous handling of external service definitions - return null; - } - $id = substr($uri, 1); - $nodes = $main_xrds->allXrdNodes; - $parser = $main_xrds->parser; - foreach ($nodes as $node) { - $attrs = $parser->attributes($node); - if (array_key_exists('xml:id', $attrs) && - $attrs['xml:id'] == $id) { - # XXX: trick the constructor into thinking this is the only node - $bogus_nodes = array($node); - return new Auth_Yadis_XRDS($parser, $bogus_nodes); - } - } - return null; - } - - function addServices($xrd, $types, &$omb) - { - foreach ($types as $type) { - $matches = omb_get_services($xrd, $type); - if ($matches) { - $omb[$type] = $matches[0]; - } else { - # no match for type - return false; - } - } - return true; - } - - function requestToken($omb) - { - $con = omb_oauth_consumer(); - - $url = omb_service_uri($omb[OAUTH_ENDPOINT_REQUEST]); - - # XXX: Is this the right thing to do? Strip off GET params and make them - # POST params? Seems wrong to me. - - $parsed = parse_url($url); - $params = array(); - parse_str($parsed['query'], $params); - - $req = OAuthRequest::from_consumer_and_token($con, null, "POST", $url, $params); - - $listener = omb_local_id($omb[OAUTH_ENDPOINT_REQUEST]); - - if (!$listener) { - return null; - } - - $req->set_parameter('omb_listener', $listener); - $req->set_parameter('omb_version', OMB_VERSION_01); - - # XXX: test to see if endpoint accepts this signature method - - $req->sign_request(omb_hmac_sha1(), $con, null); - - # We re-use this tool's fetcher, since it's pretty good - - $fetcher = Auth_Yadis_Yadis::getHTTPFetcher(); - - $result = $fetcher->post($req->get_normalized_http_url(), - $req->to_postdata(), - array('User-Agent: StatusNet/' . STATUSNET_VERSION)); - if ($result->status != 200) { - return null; - } - - parse_str($result->body, $return); - - return array($return['oauth_token'], $return['oauth_token_secret']); - } - - function requestAuthorization($user, $omb, $token, $secret) - { - $con = omb_oauth_consumer(); - $tok = new OAuthToken($token, $secret); - - $url = omb_service_uri($omb[OAUTH_ENDPOINT_AUTHORIZE]); - - # XXX: Is this the right thing to do? Strip off GET params and make them - # POST params? Seems wrong to me. - - $parsed = parse_url($url); - $params = array(); - parse_str($parsed['query'], $params); - - $req = OAuthRequest::from_consumer_and_token($con, $tok, 'GET', $url, $params); - - # We send over a ton of information. This lets the other - # server store info about our user, and it lets the current - # user decide if they really want to authorize the subscription. - - $req->set_parameter('omb_version', OMB_VERSION_01); - $req->set_parameter('omb_listener', omb_local_id($omb[OAUTH_ENDPOINT_REQUEST])); - $req->set_parameter('omb_listenee', $user->uri); - $req->set_parameter('omb_listenee_profile', common_profile_url($user->nickname)); - $req->set_parameter('omb_listenee_nickname', $user->nickname); - $req->set_parameter('omb_listenee_license', common_config('license', 'url')); - + /* Create an OMB_Profile from $user. */ $profile = $user->getProfile(); if (!$profile) { common_log_db_error($user, 'SELECT', __FILE__); @@ -367,49 +192,16 @@ class RemotesubscribeAction extends Action return; } - if (!is_null($profile->fullname)) { - $req->set_parameter('omb_listenee_fullname', $profile->fullname); - } - if (!is_null($profile->homepage)) { - $req->set_parameter('omb_listenee_homepage', $profile->homepage); - } - if (!is_null($profile->bio)) { - $req->set_parameter('omb_listenee_bio', $profile->bio); - } - if (!is_null($profile->location)) { - $req->set_parameter('omb_listenee_location', $profile->location); - } - $avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE); - if ($avatar) { - $req->set_parameter('omb_listenee_avatar', $avatar->url); - } - - # XXX: add a nonce to prevent replay attacks - - $req->set_parameter('oauth_callback', common_local_url('finishremotesubscribe')); - - # XXX: test to see if endpoint accepts this signature method - - $req->sign_request(omb_hmac_sha1(), $con, $tok); - - # store all our info here - - $omb['listenee'] = $user->nickname; - $omb['listener'] = omb_local_id($omb[OAUTH_ENDPOINT_REQUEST]); - $omb['token'] = $token; - $omb['secret'] = $secret; - # call doesn't work after bounce back so we cache; maybe serialization issue...? - $omb['access_token_url'] = omb_service_uri($omb[OAUTH_ENDPOINT_ACCESS]); - $omb['post_notice_url'] = omb_service_uri($omb[OMB_ENDPOINT_POSTNOTICE]); - $omb['update_profile_url'] = omb_service_uri($omb[OMB_ENDPOINT_UPDATEPROFILE]); + $target_url = $service->requestAuthorization( + profile_to_omb_profile($user->uri, $profile), + common_local_url('finishremotesubscribe')); common_ensure_session(); - $_SESSION['oauth_authorization_request'] = $omb; - - # Redirect to authorization service + $_SESSION['oauth_authorization_request'] = serialize($service); - common_redirect($req->to_url(), 303); - return; + /* Redirect to the remote service for authorization. */ + common_redirect($target_url, 303); } } +?> diff --git a/actions/replies.php b/actions/replies.php index cca430230..6003ad30b 100644 --- a/actions/replies.php +++ b/actions/replies.php @@ -192,9 +192,7 @@ class RepliesAction extends OwnerDesignAction } } else { - $message .= sprintf(_('Why not [register an account](%%%%action.%s%%%%) and then nudge %s or post a notice to his or her attention.'), - (!common_config('site','openidonly')) ? 'register' : 'openidlogin', - $this->user->nickname); + $message .= sprintf(_('Why not [register an account](%%%%action.register%%%%) and then nudge %s or post a notice to his or her attention.'), $this->user->nickname); } $this->elementStart('div', 'guide'); diff --git a/actions/repliesrss.php b/actions/repliesrss.php index c71c9226f..76aae21ad 100644 --- a/actions/repliesrss.php +++ b/actions/repliesrss.php @@ -38,6 +38,7 @@ class RepliesrssAction extends Rss10Action $this->clientError(_('No such user.')); return false; } else { + $this->notices = $this->getNotices($this->limit); return true; } } diff --git a/actions/requesttoken.php b/actions/requesttoken.php index a17efcdd5..e095161a7 100644 --- a/actions/requesttoken.php +++ b/actions/requesttoken.php @@ -34,6 +34,7 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { } require_once INSTALLDIR.'/lib/omb.php'; +require_once INSTALLDIR.'/extlib/libomb/service_provider.php'; /** * Request token action class. @@ -49,17 +50,17 @@ class RequesttokenAction extends Action { /** * Is read only? - * + * * @return boolean false */ - function isReadOnly($args) + function isReadOnly() { return false; } - + /** * Class handler. - * + * * @param array $args array of arguments * * @return void @@ -68,14 +69,12 @@ class RequesttokenAction extends Action { parent::handle($args); try { - common_remove_magic_from_request(); - $req = OAuthRequest::from_request('POST', common_local_url('requesttoken')); - $server = omb_oauth_server(); - $token = $server->fetch_request_token($req); - print $token.'&omb_version='.OMB_VERSION_01; - } catch (OAuthException $e) { + $srv = new OMB_Service_Provider(null, omb_oauth_datastore(), + omb_oauth_server()); + $srv->writeRequestToken(); + } catch (Exception $e) { $this->serverError($e->getMessage()); } } } - +?> diff --git a/actions/showfavorites.php b/actions/showfavorites.php index 0f7a66330..b96d2af37 100644 --- a/actions/showfavorites.php +++ b/actions/showfavorites.php @@ -196,9 +196,7 @@ class ShowfavoritesAction extends OwnerDesignAction } } else { - $message = sprintf(_('%s hasn\'t added any notices to his favorites yet. Why not [register an account](%%%%action.%s%%%%) and then post something interesting they would add to their favorites :)'), - $this->user->nickname, - (!common_config('site','openidonly')) ? 'register' : 'openidlogin'); + $message = sprintf(_('%s hasn\'t added any notices to his favorites yet. Why not [register an account](%%%%action.register%%%%) and then post something interesting they would add to their favorites :)'), $this->user->nickname); } $this->elementStart('div', 'guide'); diff --git a/actions/showgroup.php b/actions/showgroup.php index 8157ee3c8..a67765ce5 100644 --- a/actions/showgroup.php +++ b/actions/showgroup.php @@ -345,7 +345,12 @@ class ShowgroupAction extends GroupDesignAction 'method' => 'timeline', 'argument' => $this->group->nickname.'.atom')), sprintf(_('Notice feed for %s group (Atom)'), - $this->group->nickname))); + $this->group->nickname)), + new Feed(Feed::FOAF, + common_local_url('foafgroup', + array('nickname' => $this->group->nickname)), + sprintf(_('FOAF for %s group'), + $this->group->nickname))); } /** @@ -450,9 +455,8 @@ class ShowgroupAction extends GroupDesignAction $m = sprintf(_('**%s** is a user group on %%%%site.name%%%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' . 'based on the Free Software [StatusNet](http://status.net/) tool. Its members share ' . 'short messages about their life and interests. '. - '[Join now](%%%%action.%s%%%%) to become part of this group and many more! ([Read more](%%%%doc.help%%%%))'), - $this->group->nickname, - (!common_config('site','openidonly')) ? 'register' : 'openidlogin'); + '[Join now](%%%%action.register%%%%) to become part of this group and many more! ([Read more](%%%%doc.help%%%%))'), + $this->group->nickname); } else { $m = sprintf(_('**%s** is a user group on %%%%site.name%%%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' . 'based on the Free Software [StatusNet](http://status.net/) tool. Its members share ' . diff --git a/actions/shownotice.php b/actions/shownotice.php index 3bc52b2db..41408c23c 100644 --- a/actions/shownotice.php +++ b/actions/shownotice.php @@ -84,7 +84,13 @@ class ShownoticeAction extends OwnerDesignAction $this->notice = Notice::staticGet($id); if (empty($this->notice)) { - $this->clientError(_('No such notice.'), 404); + // Did we used to have it, and it got deleted? + $deleted = Deleted_notice::staticGet($id); + if (!empty($deleted)) { + $this->clientError(_('Notice deleted.'), 410); + } else { + $this->clientError(_('No such notice.'), 404); + } return false; } diff --git a/actions/showstream.php b/actions/showstream.php index 89285b13c..cdac4f47b 100644 --- a/actions/showstream.php +++ b/actions/showstream.php @@ -358,9 +358,7 @@ class ShowstreamAction extends ProfileAction } } else { - $message .= sprintf(_('Why not [register an account](%%%%action.%s%%%%) and then nudge %s or post a notice to his or her attention.'), - (!common_config('site','openidonly')) ? 'register' : 'openidlogin', - $this->user->nickname); + $message .= sprintf(_('Why not [register an account](%%%%action.register%%%%) and then nudge %s or post a notice to his or her attention.'), $this->user->nickname); } $this->elementStart('div', 'guide'); @@ -394,10 +392,8 @@ class ShowstreamAction extends ProfileAction if (!(common_config('site','closed') || common_config('site','inviteonly'))) { $m = sprintf(_('**%s** has an account on %%%%site.name%%%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' . 'based on the Free Software [StatusNet](http://status.net/) tool. ' . - '[Join now](%%%%action.%s%%%%) to follow **%s**\'s notices and many more! ([Read more](%%%%doc.help%%%%))'), - $this->user->nickname, - (!common_config('site','openidonly')) ? 'register' : 'openidlogin', - $this->user->nickname); + '[Join now](%%%%action.register%%%%) to follow **%s**\'s notices and many more! ([Read more](%%%%doc.help%%%%))'), + $this->user->nickname, $this->user->nickname); } else { $m = sprintf(_('**%s** has an account on %%%%site.name%%%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' . 'based on the Free Software [StatusNet](http://status.net/) tool. '), diff --git a/actions/subscribers.php b/actions/subscribers.php index f7d08d9d0..df9ec9961 100644 --- a/actions/subscribers.php +++ b/actions/subscribers.php @@ -111,9 +111,7 @@ class SubscribersAction extends GalleryAction } } else { - $message = sprintf(_('%s has no subscribers. Why not [register an account](%%%%action.%s%%%%) and be the first?'), - $this->user->nickname, - (!common_config('site','openidonly')) ? 'register' : 'openidlogin'); + $message = sprintf(_('%s has no subscribers. Why not [register an account](%%%%action.register%%%%) and be the first?'), $this->user->nickname); } $this->elementStart('div', 'guide'); diff --git a/actions/twitapidirect_messages.php b/actions/twitapidirect_messages.php index dbe55804b..08b8f4e9c 100644 --- a/actions/twitapidirect_messages.php +++ b/actions/twitapidirect_messages.php @@ -141,9 +141,10 @@ class Twitapidirect_messagesAction extends TwitterapiAction $code = 406, $apidata['content-type']); } else { $content_shortened = common_shorten_links($content); - if (mb_strlen($content_shortened) > 140) { - $this->clientError(_('That\'s too long. Max message size is 140 chars.'), - $code = 406, $apidata['content-type']); + if (Message::contentTooLong($content_shortened)) { + $this->clientError(sprintf(_('That\'s too long. Max message size is %d chars.'), + Message::maxContent()), + $code = 406, $apidata['content-type']); return; } } diff --git a/actions/twitapigroups.php b/actions/twitapigroups.php index 4deb1b764..a29485883 100644 --- a/actions/twitapigroups.php +++ b/actions/twitapigroups.php @@ -293,6 +293,105 @@ require_once INSTALLDIR.'/lib/twitterapi.php'; } } + function join($args, $apidata) + { + parent::handle($args); + + common_debug("in groups api action"); + + $this->auth_user = $apidata['user']; + $group = $this->get_group($apidata['api_arg'], $apidata); + + if (empty($group)) { + $this->clientError('Not Found', 404, $apidata['content-type']); + return false; + } + + if($this->auth_user->isMember($group)){ + $this->clientError(_('You are already a member of that group'), $code = 403); + return false; + } + + if (Group_block::isBlocked($group, $this->auth_user->getProfile())) { + $this->clientError(_('You have been blocked from that group by the admin.'), 403); + return false; + } + + $member = new Group_member(); + + $member->group_id = $group->id; + $member->profile_id = $this->auth_user->id; + $member->created = common_sql_now(); + + $result = $member->insert(); + + if (!$result) { + common_log_db_error($member, 'INSERT', __FILE__); + $this->serverError(sprintf(_('Could not join user %s to group %s'), + $this->auth_user->nickname, $group->nickname)); + } + + switch($apidata['content-type']) { + case 'xml': + $this->show_single_xml_group($group); + break; + case 'json': + $this->show_single_json_group($group); + break; + default: + $this->clientError(_('API method not found!'), $code = 404); + } + } + + function leave($args, $apidata) + { + parent::handle($args); + + common_debug("in groups api action"); + + $this->auth_user = $apidata['user']; + $group = $this->get_group($apidata['api_arg'], $apidata); + + if (empty($group)) { + $this->clientError('Not Found', 404, $apidata['content-type']); + return false; + } + + if(! $this->auth_user->isMember($group)){ + $this->clientError(_('You are not a member of that group'), $code = 403); + return false; + } + + $member = new Group_member(); + + $member->group_id = $group->id; + $member->profile_id = $this->auth_user->id; + + if (!$member->find(true)) { + $this->serverError(_('Could not find membership record.')); + return; + } + + $result = $member->delete(); + + if (!$result) { + common_log_db_error($member, 'INSERT', __FILE__); + $this->serverError(sprintf(_('Could not remove user %s to group %s'), + $this->auth_user->nickname, $group->nickname)); + } + + switch($apidata['content-type']) { + case 'xml': + $this->show_single_xml_group($group); + break; + case 'json': + $this->show_single_json_group($group); + break; + default: + $this->clientError(_('API method not found!'), $code = 404); + } + } + function is_member($args, $apidata) { parent::handle($args); @@ -326,4 +425,172 @@ require_once INSTALLDIR.'/lib/twitterapi.php'; $this->clientError(_('API method not found!'), $code = 404); } } + + function create($args, $apidata) + { + parent::handle($args); + + common_debug("in groups api action"); + if (!common_config('inboxes','enabled')) { + $this->serverError(_('Inboxes must be enabled for groups to work')); + return false; + } + + $this->auth_user = $apidata['user']; + + $nickname = $args['nickname']; + $fullname = $args['full_name']; + $homepage = $args['homepage']; + $description = $args['description']; + $location = $args['location']; + $aliasstring = $args['aliases']; + + if (!Validate::string($nickname, array('min_length' => 1, + 'max_length' => 64, + 'format' => NICKNAME_FMT))) { + $this->clientError(_('Nickname must have only lowercase letters '. + 'and numbers and no spaces.'), $code=403); + return; + } else if ($this->groupNicknameExists($nickname)) { + $this->clientError(_('Nickname already in use. Try another one.'), $code=403); + return; + } else if (!User_group::allowedNickname($nickname)) { + $this->clientError(_('Not a valid nickname.'), $code=403); + return; + } else if (!is_null($homepage) && (strlen($homepage) > 0) && + !Validate::uri($homepage, + array('allowed_schemes' => + array('http', 'https')))) { + $this->clientError(_('Homepage is not a valid URL.'), $code=403); + return; + } else if (!is_null($fullname) && mb_strlen($fullname) > 255) { + $this->clientError(_('Full name is too long (max 255 chars).'), $code=403); + return; + } else if (User_group::descriptionTooLong($description)) { + $this->clientError(sprintf(_('description is too long (max %d chars).'), User_group::maxDescription()), $code=403); + return; + } else if (!is_null($location) && mb_strlen($location) > 255) { + $this->clientError(_('Location is too long (max 255 chars).'), $code=403); + return; + } + + if (!empty($aliasstring)) { + $aliases = array_map('common_canonical_nickname', array_unique(preg_split('/[\s,]+/', $aliasstring))); + } else { + $aliases = array(); + } + + if (count($aliases) > common_config('group', 'maxaliases')) { + $this->clientError(sprintf(_('Too many aliases! Maximum %d.'), + common_config('group', 'maxaliases')), $code=403); + return; + } + + foreach ($aliases as $alias) { + if (!Validate::string($alias, array('min_length' => 1, + 'max_length' => 64, + 'format' => NICKNAME_FMT))) { + $this->clientError(sprintf(_('Invalid alias: "%s"'), $alias), $code=403); + return; + } + if ($this->groupNicknameExists($alias)) { + $this->clientError(sprintf(_('Alias "%s" already in use. Try another one.'), + $alias), $code=403); + return; + } + // XXX assumes alphanum nicknames + if (strcmp($alias, $nickname) == 0) { + $this->clientError(_('Alias can\'t be the same as nickname.'), $code=403); + return; + } + } + + $group = new User_group(); + + $group->query('BEGIN'); + + $group->nickname = $nickname; + $group->fullname = $fullname; + $group->homepage = $homepage; + $group->description = $description; + $group->location = $location; + $group->created = common_sql_now(); + + $result = $group->insert(); + + if (!$result) { + common_log_db_error($group, 'INSERT', __FILE__); + $this->serverError(_('Could not create group.')); + } + + $result = $group->setAliases($aliases); + + if (!$result) { + $this->serverError(_('Could not create aliases.')); + } + + $member = new Group_member(); + + $member->group_id = $group->id; + $member->profile_id = $this->auth_user->id; + $member->is_admin = 1; + $member->created = $group->created; + + $result = $member->insert(); + + if (!$result) { + common_log_db_error($member, 'INSERT', __FILE__); + $this->serverError(_('Could not set group membership.')); + } + + $group->query('COMMIT'); + + switch($apidata['content-type']) { + case 'xml': + $this->show_single_xml_group($group); + break; + case 'json': + $this->show_single_json_group($group); + break; + default: + $this->clientError(_('API method not found!'), $code = 404); + } + } + + function update($args, $apidata) + { + die("todo"); + } + + function update_group_logo($args, $apidata) + { + die("todo"); + } + + function destroy($args, $apidata) + { + die("todo"); + } + + function tag($args, $apidata) + { + die("todo"); + } + + function groupNicknameExists($nickname) + { + $group = User_group::staticGet('nickname', $nickname); + + if (!empty($group)) { + return true; + } + + $alias = Group_alias::staticGet('alias', $nickname); + + if (!empty($alias)) { + return true; + } + + return false; + } } diff --git a/actions/twitapistatuses.php b/actions/twitapistatuses.php index 360dff27c..c589bd9b1 100644 --- a/actions/twitapistatuses.php +++ b/actions/twitapistatuses.php @@ -247,14 +247,15 @@ class TwitapistatusesAction extends TwitterapiAction $status_shortened = common_shorten_links($status); - if (mb_strlen($status_shortened) > 140) { + if (Notice::contentTooLong($status_shortened)) { // XXX: Twitter truncates anything over 140, flags the status // as "truncated." Sending this error may screw up some clients // that assume Twitter will truncate for them. Should we just // truncate too? -- Zach - $this->clientError(_('That\'s too long. Max notice size is 140 chars.'), - $code = 406, $apidata['content-type']); + $this->clientError(sprintf(_('That\'s too long. Max notice size is %d chars.'), + Notice::maxContent()), + $code = 406, $apidata['content-type']); return; } } @@ -296,11 +297,6 @@ class TwitapistatusesAction extends TwitterapiAction html_entity_decode($status, ENT_NOQUOTES, 'UTF-8'), $source, 1, $reply_to); - if (is_string($notice)) { - $this->serverError($notice, 500, $apidata['content-type']); - return; - } - common_broadcast_notice($notice); $apidata['api_arg'] = $notice->id; } @@ -401,8 +397,14 @@ class TwitapistatusesAction extends TwitterapiAction } else { // XXX: Twitter just sets a 404 header and doens't bother // to return an err msg - $this->clientError(_('No status with that ID found.'), - 404, $apidata['content-type']); + $deleted = Deleted_notice::staticGet($notice_id); + if (!empty($deleted)) { + $this->clientError(_('Status deleted.'), + 410, $apidata['content-type']); + } else { + $this->clientError(_('No status with that ID found.'), + 404, $apidata['content-type']); + } } } diff --git a/actions/updateprofile.php b/actions/updateprofile.php index 9a4cf8e46..3cec9523c 100644 --- a/actions/updateprofile.php +++ b/actions/updateprofile.php @@ -1,5 +1,16 @@ <?php -/* +/** + * Handle an updateprofile action + * + * PHP version 5 + * + * @category Action + * @package StatusNet + * @author Evan Prodromou <evan@status.net> + * @author Robin Millette <millette@status.net> + * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 + * @link http://status.net/ + * * StatusNet - the distributed open-source microblogging tool * Copyright (C) 2008, 2009, StatusNet, Inc. * @@ -19,165 +30,54 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } -require_once(INSTALLDIR.'/lib/omb.php'); +require_once INSTALLDIR.'/lib/omb.php'; +require_once INSTALLDIR.'/extlib/libomb/service_provider.php'; +/** + * Handle an updateprofile action + * + * @category Action + * @package Laconica + * @author Evan Prodromou <evan@status.net> + * @author Robin Millette <millette@controlyourself.ca> + * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 + * @link http://laconi.ca/ + */ class UpdateprofileAction extends Action { - - function handle($args) - { - parent::handle($args); - try { - common_remove_magic_from_request(); - $req = OAuthRequest::from_request('POST', common_local_url('updateprofile')); - # Note: server-to-server function! - $server = omb_oauth_server(); - list($consumer, $token) = $server->verify_request($req); - if ($this->update_profile($req, $consumer, $token)) { - header('HTTP/1.1 200 OK'); - header('Content-type: text/plain'); - print "omb_version=".OMB_VERSION_01; - } - } catch (OAuthException $e) { - $this->serverError($e->getMessage()); - return; - } - } - function update_profile($req, $consumer, $token) + /** + * For initializing members of the class. + * + * @param array $argarray misc. arguments + * + * @return boolean true + */ + function prepare($argarray) { - $version = $req->get_parameter('omb_version'); - if ($version != OMB_VERSION_01) { - $this->clientError(_('Unsupported OMB version'), 400); + parent::prepare($argarray); + $license = $_POST['omb_listenee_license']; + $site_license = common_config('license', 'url'); + if (!common_compatible_license($license, $site_license)) { + $this->clientError(sprintf(_('Listenee stream license ‘%s’ is not '. + 'compatible with site license ‘%s’.'), + $license, $site_license)); return false; } - # First, check to see if listenee exists - $listenee = $req->get_parameter('omb_listenee'); - $remote = Remote_profile::staticGet('uri', $listenee); - if (!$remote) { - $this->clientError(_('Profile unknown'), 404); - return false; - } - # Second, check to see if they should be able to post updates! - # We see if there are any subscriptions to that remote user with - # the given token. - - $sub = new Subscription(); - $sub->subscribed = $remote->id; - $sub->token = $token->key; - if (!$sub->find(true)) { - $this->clientError(_('You did not send us that profile'), 403); - return false; - } - - $profile = Profile::staticGet('id', $remote->id); - if (!$profile) { - # This one is our fault - $this->serverError(_('Remote profile with no matching profile'), 500); - return false; - } - $nickname = $req->get_parameter('omb_listenee_nickname'); - if ($nickname && !Validate::string($nickname, array('min_length' => 1, - 'max_length' => 64, - 'format' => NICKNAME_FMT))) { - $this->clientError(_('Nickname must have only lowercase letters and numbers and no spaces.')); - return false; - } - $license = $req->get_parameter('omb_listenee_license'); - if ($license && !common_valid_http_url($license)) { - $this->clientError(sprintf(_("Invalid license URL '%s'"), $license)); - return false; - } - $profile_url = $req->get_parameter('omb_listenee_profile'); - if ($profile_url && !common_valid_http_url($profile_url)) { - $this->clientError(sprintf(_("Invalid profile URL '%s'."), $profile_url)); - return false; - } - # optional stuff - $fullname = $req->get_parameter('omb_listenee_fullname'); - if ($fullname && mb_strlen($fullname) > 255) { - $this->clientError(_("Full name is too long (max 255 chars).")); - return false; - } - $homepage = $req->get_parameter('omb_listenee_homepage'); - if ($homepage && (!common_valid_http_url($homepage) || mb_strlen($homepage) > 255)) { - $this->clientError(sprintf(_("Invalid homepage '%s'"), $homepage)); - return false; - } - $bio = $req->get_parameter('omb_listenee_bio'); - if ($bio && mb_strlen($bio) > 140) { - $this->clientError(_("Bio is too long (max 140 chars).")); - return false; - } - $location = $req->get_parameter('omb_listenee_location'); - if ($location && mb_strlen($location) > 255) { - $this->clientError(_("Location is too long (max 255 chars).")); - return false; - } - $avatar = $req->get_parameter('omb_listenee_avatar'); - if ($avatar) { - if (!common_valid_http_url($avatar) || strlen($avatar) > 255) { - $this->clientError(sprintf(_("Invalid avatar URL '%s'"), $avatar)); - return false; - } - $size = @getimagesize($avatar); - if (!$size) { - $this->clientError(sprintf(_("Can't read avatar URL '%s'"), $avatar)); - return false; - } - if ($size[0] != AVATAR_PROFILE_SIZE || $size[1] != AVATAR_PROFILE_SIZE) { - $this->clientError(sprintf(_("Wrong size image at '%s'"), $avatar)); - return false; - } - if (!in_array($size[2], array(IMAGETYPE_GIF, IMAGETYPE_JPEG, - IMAGETYPE_PNG))) { - $this->clientError(sprintf(_("Wrong image type for '%s'"), $avatar)); - return false; - } - } - - $orig_profile = clone($profile); + return true; + } - /* Use values even if they are an empty string. Parsing an empty string in - updateProfile is the specified way of clearing a parameter in OMB. */ - if (!is_null($nickname)) { - $profile->nickname = $nickname; - } - if (!is_null($profile_url)) { - $profile->profileurl = $profile_url; - } - if (!is_null($fullname)) { - $profile->fullname = $fullname; - } - if (!is_null($homepage)) { - $profile->homepage = $homepage; - } - if (!is_null($bio)) { - $profile->bio = $bio; - } - if (!is_null($location)) { - $profile->location = $location; - } + function handle($args) + { + parent::handle($args); - if (!$profile->update($orig_profile)) { - $this->serverError(_('Could not save new profile info'), 500); - return false; - } else { - if ($avatar) { - $temp_filename = tempnam(sys_get_temp_dir(), 'listenee_avatar'); - copy($avatar, $temp_filename); - $imagefile = new ImageFile($profile->id, $temp_filename); - $filename = Avatar::filename($profile->id, - image_type_to_extension($imagefile->type), - null, - common_timestamp()); - rename($temp_filename, Avatar::path($filename)); - if (!$profile->setOriginal($filename)) { - $this->serverError(_('Could not save avatar info'), 500); - return false; - } - } - return true; + try { + $srv = new OMB_Service_Provider(null, omb_oauth_datastore(), + omb_oauth_server()); + $srv->handleUpdateProfile(); + } catch (Exception $e) { + $this->serverError($e->getMessage()); + return; } } } diff --git a/actions/userauthorization.php b/actions/userauthorization.php index a9ac1f256..dc59e6c94 100644 --- a/actions/userauthorization.php +++ b/actions/userauthorization.php @@ -1,5 +1,16 @@ <?php -/* +/** + * Let the user authorize a remote subscription request + * + * PHP version 5 + * + * @category Action + * @package StatusNet + * @author Evan Prodromou <evan@status.net> + * @author Robin Millette <millette@status.net> + * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 + * @link http://status.net/ + * * StatusNet - the distributed open-source microblogging tool * Copyright (C) 2008, 2009, StatusNet, Inc. * @@ -19,7 +30,9 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } -require_once(INSTALLDIR.'/lib/omb.php'); +require_once INSTALLDIR.'/lib/omb.php'; +require_once INSTALLDIR.'/extlib/libomb/service_provider.php'; +require_once INSTALLDIR.'/extlib/libomb/profile.php'; define('TIMESTAMP_THRESHOLD', 300); class UserauthorizationAction extends Action @@ -32,46 +45,58 @@ class UserauthorizationAction extends Action parent::handle($args); if ($_SERVER['REQUEST_METHOD'] == 'POST') { - # CSRF protection + /* Use a session token for CSRF protection. */ $token = $this->trimmed('token'); if (!$token || $token != common_session_token()) { - $params = $this->getStoredParams(); - $this->showForm($params, _('There was a problem with your session token. '. - 'Try again, please.')); + $srv = $this->getStoredParams(); + $this->showForm($srv->getRemoteUser(), _('There was a problem ' . + 'with your session token. Try again, ' . + 'please.')); return; } - # We've shown the form, now post user's choice + /* We've shown the form, now post user's choice. */ $this->sendAuthorization(); } else { if (!common_logged_in()) { - # Go log in, and then come back + /* Go log in, and then come back. */ common_set_returnto($_SERVER['REQUEST_URI']); - if (!common_config('site', 'openidonly')) { - common_redirect(common_local_url('login')); - } else { - common_redirect(common_local_url('openidlogin')); - } + common_redirect(common_local_url('login')); + return; + } + + $user = common_current_user(); + $profile = $user->getProfile(); + if (!$profile) { + common_log_db_error($user, 'SELECT', __FILE__); + $this->serverError(_('User without matching profile')); return; } + /* TODO: If no token is passed the user should get a prompt to enter + it according to OAuth Core 1.0. */ try { - $this->validateRequest(); - $this->storeParams($_GET); - $this->showForm($_GET); - } catch (OAuthException $e) { + $this->validateOmb(); + $srv = new OMB_Service_Provider( + profile_to_omb_profile($user->uri, $profile), + omb_oauth_datastore()); + + $remote_user = $srv->handleUserAuth(); + } catch (Exception $e) { $this->clearParams(); $this->clientError($e->getMessage()); return; } + $this->storeParams($srv); + $this->showForm($remote_user); } } function showForm($params, $error=null) { $this->params = $params; - $this->error = $error; + $this->error = $error; $this->showPage(); } @@ -83,23 +108,24 @@ class UserauthorizationAction extends Action function showPageNotice() { $this->element('p', null, _('Please check these details to make sure '. - 'that you want to subscribe to this user\'s notices. '. - 'If you didn\'t just ask to subscribe to someone\'s notices, '. - 'click "Reject".')); + 'that you want to subscribe to this ' . + 'user’s notices. If you didn’t just ask ' . + 'to subscribe to someone’s notices, '. + 'click “Reject”.')); } function showContent() { $params = $this->params; - $nickname = $params['omb_listenee_nickname']; - $profile = $params['omb_listenee_profile']; - $license = $params['omb_listenee_license']; - $fullname = $params['omb_listenee_fullname']; - $homepage = $params['omb_listenee_homepage']; - $bio = $params['omb_listenee_bio']; - $location = $params['omb_listenee_location']; - $avatar = $params['omb_listenee_avatar']; + $nickname = $params->getNickname(); + $profile = $params->getProfileURL(); + $license = $params->getLicenseURL(); + $fullname = $params->getFullname(); + $homepage = $params->getHomepage(); + $bio = $params->getBio(); + $location = $params->getLocation(); + $avatar = $params->getAvatarURL(); $this->elementStart('div', array('class' => 'profile')); $this->elementStart('div', 'entity_profile vcard'); @@ -176,11 +202,14 @@ class UserauthorizationAction extends Action 'id' => 'userauthorization', 'class' => 'form_user_authorization', 'name' => 'userauthorization', - 'action' => common_local_url('userauthorization'))); + 'action' => common_local_url( + 'userauthorization'))); $this->hidden('token', common_session_token()); - $this->submit('accept', _('Accept'), 'submit accept', null, _('Subscribe to this user')); - $this->submit('reject', _('Reject'), 'submit reject', null, _('Reject this subscription')); + $this->submit('accept', _('Accept'), 'submit accept', null, + _('Subscribe to this user')); + $this->submit('reject', _('Reject'), 'submit reject', null, + _('Reject this subscription')); $this->elementEnd('form'); $this->elementEnd('li'); $this->elementEnd('ul'); @@ -190,191 +219,27 @@ class UserauthorizationAction extends Action function sendAuthorization() { - $params = $this->getStoredParams(); + $srv = $this->getStoredParams(); - if (!$params) { + if (is_null($srv)) { $this->clientError(_('No authorization request!')); return; } - $callback = $params['oauth_callback']; - - if ($this->arg('accept')) { - if (!$this->authorizeToken($params)) { - $this->clientError(_('Error authorizing token')); - } - if (!$this->saveRemoteProfile($params)) { - $this->clientError(_('Error saving remote profile')); - } - if (!$callback) { - $this->showAcceptMessage($params['oauth_token']); - } else { - $newparams = array(); - $newparams['oauth_token'] = $params['oauth_token']; - $newparams['omb_version'] = OMB_VERSION_01; - $user = User::staticGet('uri', $params['omb_listener']); - $profile = $user->getProfile(); - if (!$profile) { - common_log_db_error($user, 'SELECT', __FILE__); - $this->serverError(_('User without matching profile')); - return; - } - $newparams['omb_listener_nickname'] = $user->nickname; - $newparams['omb_listener_profile'] = common_local_url('showstream', - array('nickname' => $user->nickname)); - if (!is_null($profile->fullname)) { - $newparams['omb_listener_fullname'] = $profile->fullname; - } - if (!is_null($profile->homepage)) { - $newparams['omb_listener_homepage'] = $profile->homepage; - } - if (!is_null($profile->bio)) { - $newparams['omb_listener_bio'] = $profile->bio; - } - if (!is_null($profile->location)) { - $newparams['omb_listener_location'] = $profile->location; - } - $avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE); - if ($avatar) { - $newparams['omb_listener_avatar'] = $avatar->url; - } - $parts = array(); - foreach ($newparams as $k => $v) { - $parts[] = $k . '=' . OAuthUtil::urlencode_rfc3986($v); - } - $query_string = implode('&', $parts); - $parsed = parse_url($callback); - $url = $callback . (($parsed['query']) ? '&' : '?') . $query_string; - common_redirect($url, 303); - } - } else { - if (!$callback) { - $this->showRejectMessage(); - } else { - # XXX: not 100% sure how to signal failure... just redirect without token? - common_redirect($callback, 303); - } - } - } - - function authorizeToken(&$params) - { - $token_field = $params['oauth_token']; - $rt = new Token(); - $rt->tok = $token_field; - $rt->type = 0; - $rt->state = 0; - if ($rt->find(true)) { - $orig_rt = clone($rt); - $rt->state = 1; # Authorized but not used - if ($rt->update($orig_rt)) { - return true; - } - } - return false; - } - - # XXX: refactor with similar code in finishremotesubscribe.php - - function saveRemoteProfile(&$params) - { - # FIXME: we should really do this when the consumer comes - # back for an access token. If they never do, we've got stuff in a - # weird state. - - $nickname = $params['omb_listenee_nickname']; - $fullname = $params['omb_listenee_fullname']; - $profile_url = $params['omb_listenee_profile']; - $homepage = $params['omb_listenee_homepage']; - $bio = $params['omb_listenee_bio']; - $location = $params['omb_listenee_location']; - $avatar_url = $params['omb_listenee_avatar']; - - $listenee = $params['omb_listenee']; - $remote = Remote_profile::staticGet('uri', $listenee); - - if ($remote) { - $exists = true; - $profile = Profile::staticGet($remote->id); - $orig_remote = clone($remote); - $orig_profile = clone($profile); - } else { - $exists = false; - $remote = new Remote_profile(); - $remote->uri = $listenee; - $profile = new Profile(); - } - - $profile->nickname = $nickname; - $profile->profileurl = $profile_url; - - if (!is_null($fullname)) { - $profile->fullname = $fullname; - } - if (!is_null($homepage)) { - $profile->homepage = $homepage; - } - if (!is_null($bio)) { - $profile->bio = $bio; - } - if (!is_null($location)) { - $profile->location = $location; + $accepted = $this->arg('accept'); + try { + list($val, $token) = $srv->continueUserAuth($accepted); + } catch (Exception $e) { + $this->clientError($e->getMessage()); + return; } - - if ($exists) { - $profile->update($orig_profile); + if ($val !== false) { + common_redirect($val, 303); + } elseif ($accepted) { + $this->showAcceptMessage($token); } else { - $profile->created = DB_DataObject_Cast::dateTime(); # current time - $id = $profile->insert(); - if (!$id) { - return false; - } - $remote->id = $id; + $this->showRejectMessage(); } - - if ($exists) { - if (!$remote->update($orig_remote)) { - return false; - } - } else { - $remote->created = DB_DataObject_Cast::dateTime(); # current time - if (!$remote->insert()) { - return false; - } - } - - if ($avatar_url) { - if (!$this->addAvatar($profile, $avatar_url)) { - return false; - } - } - - $user = common_current_user(); - - $sub = new Subscription(); - $sub->subscriber = $user->id; - $sub->subscribed = $remote->id; - $sub->token = $params['oauth_token']; # NOTE: request token, not valid for use! - $sub->created = DB_DataObject_Cast::dateTime(); # current time - - if (!$sub->insert()) { - return false; - } - - return true; - } - - function addAvatar($profile, $url) - { - $temp_filename = tempnam(sys_get_temp_dir(), 'listenee_avatar'); - copy($url, $temp_filename); - $imagefile = new ImageFile($profile->id, $temp_filename); - $filename = Avatar::filename($profile->id, - image_type_to_extension($imagefile->type), - null, - common_timestamp()); - rename($temp_filename, Avatar::path($filename)); - return $profile->setOriginal($filename); } function showAcceptMessage($tok) @@ -382,26 +247,28 @@ class UserauthorizationAction extends Action common_show_header(_('Subscription authorized')); $this->element('p', null, _('The subscription has been authorized, but no '. - 'callback URL was passed. Check with the site\'s instructions for '. - 'details on how to authorize the subscription. Your subscription token is:')); + 'callback URL was passed. Check with the site’s ' . + 'instructions for details on how to authorize the ' . + 'subscription. Your subscription token is:')); $this->element('blockquote', 'token', $tok); common_show_footer(); } - function showRejectMessage($tok) + function showRejectMessage() { common_show_header(_('Subscription rejected')); $this->element('p', null, _('The subscription has been rejected, but no '. - 'callback URL was passed. Check with the site\'s instructions for '. - 'details on how to fully reject the subscription.')); + 'callback URL was passed. Check with the site’s ' . + 'instructions for details on how to fully reject ' . + 'the subscription.')); common_show_footer(); } function storeParams($params) { common_ensure_session(); - $_SESSION['userauthorizationparams'] = $params; + $_SESSION['userauthorizationparams'] = serialize($params); } function clearParams() @@ -413,138 +280,74 @@ class UserauthorizationAction extends Action function getStoredParams() { common_ensure_session(); - $params = $_SESSION['userauthorizationparams']; + $params = unserialize($_SESSION['userauthorizationparams']); return $params; } - # Throws an OAuthException if anything goes wrong - - function validateRequest() - { - /* Find token. - TODO: If no token is passed the user should get a prompt to enter it - according to OAuth Core 1.0 */ - $t = new Token(); - $t->tok = $_GET['oauth_token']; - $t->type = 0; - if (!$t->find(true)) { - throw new OAuthException("Invalid request token: " . $_GET['oauth_token']); - } - - $this->validateOmb(); - return true; - } - function validateOmb() { - foreach (array('omb_version', 'omb_listener', 'omb_listenee', - 'omb_listenee_profile', 'omb_listenee_nickname', - 'omb_listenee_license') as $param) - { - if (!isset($_GET[$param]) || is_null($_GET[$param])) { - throw new OAuthException("Required parameter '$param' not found"); - } - } - # Now, OMB stuff - $version = $_GET['omb_version']; - if ($version != OMB_VERSION_01) { - throw new OAuthException("OpenMicroBlogging version '$version' not supported"); - } $listener = $_GET['omb_listener']; + $listenee = $_GET['omb_listenee']; + $nickname = $_GET['omb_listenee_nickname']; + $profile = $_GET['omb_listenee_profile']; + $user = User::staticGet('uri', $listener); if (!$user) { - throw new OAuthException("Listener URI '$listener' not found here"); - } - $cur = common_current_user(); - if ($cur->id != $user->id) { - throw new OAuthException("Can't add for another user!"); - } - $listenee = $_GET['omb_listenee']; - if (!Validate::uri($listenee) && - !common_valid_tag($listenee)) { - throw new OAuthException("Listenee URI '$listenee' not a recognizable URI"); + throw new Exception(sprintf(_('Listener URI ‘%s’ not found here'), + $listener)); } + if (strlen($listenee) > 255) { - throw new OAuthException("Listenee URI '$listenee' too long"); + throw new Exception(sprintf(_('Listenee URI ‘%s’ is too long.'), + $listenee)); } $other = User::staticGet('uri', $listenee); if ($other) { - throw new OAuthException("Listenee URI '$listenee' is local user"); + throw new Exception(sprintf(_('Listenee URI ‘%s’ is a local user.'), + $listenee)); } $remote = Remote_profile::staticGet('uri', $listenee); if ($remote) { - $sub = new Subscription(); + $sub = new Subscription(); $sub->subscriber = $user->id; $sub->subscribed = $remote->id; if ($sub->find(true)) { - throw new OAuthException("Already subscribed to user!"); + throw new Exception('You are already subscribed to this user.'); } } - $nickname = $_GET['omb_listenee_nickname']; - if (!Validate::string($nickname, array('min_length' => 1, - 'max_length' => 64, - 'format' => NICKNAME_FMT))) { - throw new OAuthException('Nickname must have only letters and numbers and no spaces.'); - } - $profile = $_GET['omb_listenee_profile']; - if (!common_valid_http_url($profile)) { - throw new OAuthException("Invalid profile URL '$profile'."); - } - if ($profile == common_local_url('showstream', array('nickname' => $nickname))) { - throw new OAuthException("Profile URL '$profile' is for a local user."); - } + if ($profile == common_profile_url($nickname)) { + throw new Exception(sprintf(_('Profile URL ‘%s’ is for a local user.'), + $profile)); - $license = $_GET['omb_listenee_license']; - if (!common_valid_http_url($license)) { - throw new OAuthException("Invalid license URL '$license'."); } + + $license = $_GET['omb_listenee_license']; $site_license = common_config('license', 'url'); if (!common_compatible_license($license, $site_license)) { - throw new OAuthException("Listenee stream license '$license' not compatible with site license '$site_license'."); - } - # optional stuff - $fullname = $_GET['omb_listenee_fullname']; - if ($fullname && mb_strlen($fullname) > 255) { - throw new OAuthException("Full name '$fullname' too long."); - } - $homepage = $_GET['omb_listenee_homepage']; - if ($homepage && (!common_valid_http_url($homepage) || mb_strlen($homepage) > 255)) { - throw new OAuthException("Invalid homepage '$homepage'"); - } - $bio = $_GET['omb_listenee_bio']; - if ($bio && mb_strlen($bio) > 140) { - throw new OAuthException("Bio too long '$bio'"); - } - $location = $_GET['omb_listenee_location']; - if ($location && mb_strlen($location) > 255) { - throw new OAuthException("Location too long '$location'"); + throw new Exception(sprintf(_('Listenee stream license ‘%s’ is not ' . + 'compatible with site license ‘%s’.'), + $license, $site_license)); } + $avatar = $_GET['omb_listenee_avatar']; if ($avatar) { if (!common_valid_http_url($avatar) || strlen($avatar) > 255) { - throw new OAuthException("Invalid avatar URL '$avatar'"); + throw new Exception(sprintf(_('Avatar URL ‘%s’ is not valid.'), + $avatar)); } $size = @getimagesize($avatar); if (!$size) { - throw new OAuthException("Can't read avatar URL '$avatar'"); - } - if ($size[0] != AVATAR_PROFILE_SIZE || $size[1] != AVATAR_PROFILE_SIZE) { - throw new OAuthException("Wrong size image at '$avatar'"); + throw new Exception(sprintf(_('Can’t read avatar URL ‘%s’.'), + $avatar)); } if (!in_array($size[2], array(IMAGETYPE_GIF, IMAGETYPE_JPEG, IMAGETYPE_PNG))) { - throw new OAuthException("Wrong image type for '$avatar'"); + throw new Exception(sprintf(_('Wrong image type for avatar URL '. + '‘%s’.'), $avatar)); } } - $callback = $_GET['oauth_callback']; - if ($callback && !common_valid_http_url($callback)) { - throw new OAuthException("Invalid callback URL '$callback'"); - } - if ($callback && $callback == common_local_url('finishremotesubscribe')) { - throw new OAuthException("Callback URL '$callback' is for local site."); - } } -} +}
\ No newline at end of file diff --git a/actions/userrss.php b/actions/userrss.php index fa6d588cd..19e610551 100644 --- a/actions/userrss.php +++ b/actions/userrss.php @@ -25,7 +25,6 @@ require_once(INSTALLDIR.'/lib/rssaction.php'); class UserrssAction extends Rss10Action { - var $user = null; var $tag = null; function prepare($args) @@ -39,6 +38,7 @@ class UserrssAction extends Rss10Action $this->clientError(_('No such user.')); return false; } else { + $this->notices = $this->getNotices($this->limit); return true; } } @@ -64,9 +64,8 @@ class UserrssAction extends Rss10Action function getNotices($limit=0) { - $user = $this->user; - + if (is_null($user)) { return null; } diff --git a/actions/xrds.php b/actions/xrds.php index def10e4cf..8ba89fec0 100644 --- a/actions/xrds.php +++ b/actions/xrds.php @@ -1,7 +1,7 @@ <?php /** - * XRDS for OpenID + * XRDS for OpenMicroBlogging * * PHP version 5 * @@ -34,9 +34,11 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { } require_once INSTALLDIR.'/lib/omb.php'; +require_once INSTALLDIR.'/extlib/libomb/service_provider.php'; +require_once INSTALLDIR.'/extlib/libomb/xrds_mapper.php'; /** - * XRDS for OpenID + * XRDS for OpenMicroBlogging * * @category Action * @package StatusNet @@ -52,7 +54,7 @@ class XrdsAction extends Action * * @return boolean true */ - function isReadOnly($args) + function isReadOnly() { return true; } @@ -85,89 +87,31 @@ class XrdsAction extends Action */ function showXrds($user) { - header('Content-Type: application/xrds+xml'); - $this->startXML(); - $this->elementStart('XRDS', array('xmlns' => 'xri://$xrds')); + $srv = new OMB_Service_Provider(profile_to_omb_profile($user->uri, + $user->getProfile())); + /* Use libomb’s default XRDS Writer. */ + $xrds_writer = null; + $srv->writeXRDS(new Laconica_XRDS_Mapper(), $xrds_writer); + } +} - $this->elementStart('XRD', array('xmlns' => 'xri://$xrd*($v*2.0)', - 'xml:id' => 'oauth', - 'xmlns:simple' => 'http://xrds-simple.net/core/1.0', - 'version' => '2.0')); - $this->element('Type', null, 'xri://$xrds*simple'); - $this->showService(OAUTH_ENDPOINT_REQUEST, - common_local_url('requesttoken'), - array(OAUTH_AUTH_HEADER, OAUTH_POST_BODY), - array(OAUTH_HMAC_SHA1), - $user->uri); - $this->showService(OAUTH_ENDPOINT_AUTHORIZE, - common_local_url('userauthorization'), - array(OAUTH_AUTH_HEADER, OAUTH_POST_BODY), - array(OAUTH_HMAC_SHA1)); - $this->showService(OAUTH_ENDPOINT_ACCESS, - common_local_url('accesstoken'), - array(OAUTH_AUTH_HEADER, OAUTH_POST_BODY), - array(OAUTH_HMAC_SHA1)); - $this->showService(OAUTH_ENDPOINT_RESOURCE, - null, - array(OAUTH_AUTH_HEADER, OAUTH_POST_BODY), - array(OAUTH_HMAC_SHA1)); - $this->elementEnd('XRD'); +class Laconica_XRDS_Mapper implements OMB_XRDS_Mapper +{ + protected $urls; - // XXX: decide whether to include user's ID/nickname in postNotice URL - $this->elementStart('XRD', array('xmlns' => 'xri://$xrd*($v*2.0)', - 'xml:id' => 'omb', - 'xmlns:simple' => 'http://xrds-simple.net/core/1.0', - 'version' => '2.0')); - $this->element('Type', null, 'xri://$xrds*simple'); - $this->showService(OMB_ENDPOINT_POSTNOTICE, - common_local_url('postnotice')); - $this->showService(OMB_ENDPOINT_UPDATEPROFILE, - common_local_url('updateprofile')); - $this->elementEnd('XRD'); - $this->elementStart('XRD', array('xmlns' => 'xri://$xrd*($v*2.0)', - 'version' => '2.0')); - $this->element('Type', null, 'xri://$xrds*simple'); - $this->showService(OAUTH_DISCOVERY, - '#oauth'); - $this->showService(OMB_NAMESPACE, - '#omb'); - $this->elementEnd('XRD'); - $this->elementEnd('XRDS'); - $this->endXML(); + public function __construct() + { + $this->urls = array( + OAUTH_ENDPOINT_REQUEST => 'requesttoken', + OAUTH_ENDPOINT_AUTHORIZE => 'userauthorization', + OAUTH_ENDPOINT_ACCESS => 'accesstoken', + OMB_ENDPOINT_POSTNOTICE => 'postnotice', + OMB_ENDPOINT_UPDATEPROFILE => 'updateprofile'); } - /** - * Show service. - * - * @param string $type XRDS type - * @param string $uri URI - * @param array $params type parameters, null by default - * @param array $sigs type signatures, null by default - * @param string $localId local ID, null by default - * - * @return void - */ - function showService($type, $uri, $params=null, $sigs=null, $localId=null) + public function getURL($action) { - $this->elementStart('Service'); - if ($uri) { - $this->element('URI', null, $uri); - } - $this->element('Type', null, $type); - if ($params) { - foreach ($params as $param) { - $this->element('Type', null, $param); - } - } - if ($sigs) { - foreach ($sigs as $sig) { - $this->element('Type', null, $sig); - } - } - if ($localId) { - $this->element('LocalID', null, $localId); - } - $this->elementEnd('Service'); + return common_local_url($this->urls[$action]); } } - +?> |