From e8b6d7c946da5fb2ce5397bccfd332de8ca1f9dd Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 19 Oct 2010 20:54:53 -0700 Subject: Add support for an anonymous OAuth consumer. Note: this requires a small DB tweak. Oauth_application_user needs to have the primary compound key: (profile_id, application_id, token). http://status.net/open-source/issues/2761 This should also make it possible to have multiple access tokens per application. http://status.net/open-source/issues/2788 --- classes/Oauth_application_user.php | 41 +++++++++++++++++++++++++++++++++----- classes/Profile.php | 10 +++++----- classes/statusnet.ini | 3 ++- 3 files changed, 43 insertions(+), 11 deletions(-) (limited to 'classes') diff --git a/classes/Oauth_application_user.php b/classes/Oauth_application_user.php index 3d4238d64..fcf6553ff 100644 --- a/classes/Oauth_application_user.php +++ b/classes/Oauth_application_user.php @@ -13,7 +13,7 @@ class Oauth_application_user extends Memcached_DataObject public $profile_id; // int(4) primary_key not_null public $application_id; // int(4) primary_key not_null public $access_type; // tinyint(1) - public $token; // varchar(255) + public $token; // varchar(255) primary_key not_null public $created; // datetime not_null public $modified; // timestamp not_null default_CURRENT_TIMESTAMP @@ -24,20 +24,51 @@ class Oauth_application_user extends Memcached_DataObject /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE - static function getByKeys($user, $app) + static function getByUserAndToken($user, $token) { - if (empty($user) || empty($app)) { + if (empty($user) || empty($token)) { return null; } $oau = new Oauth_application_user(); - $oau->profile_id = $user->id; - $oau->application_id = $app->id; + $oau->profile_id = $user->id; + $oau->token = $token; $oau->limit(1); $result = $oau->find(true); return empty($result) ? null : $oau; } + + function updateKeys(&$orig) + { + $this->_connect(); + $parts = array(); + foreach (array('profile_id', 'application_id', 'token', 'access_type') as $k) { + if (strcmp($this->$k, $orig->$k) != 0) { + $parts[] = $k . ' = ' . $this->_quote($this->$k); + } + } + if (count($parts) == 0) { + # No changes + return true; + } + $toupdate = implode(', ', $parts); + + $table = $this->tableName(); + if(common_config('db','quote_identifiers')) { + $table = '"' . $table . '"'; + } + $qry = 'UPDATE ' . $table . ' SET ' . $toupdate . + ' WHERE profile_id = ' . $orig->profile_id + . ' AND application_id = ' . $orig->application_id + . " AND token = '$orig->token'"; + $orig->decache(); + $result = $this->query($qry); + if ($result) { + $this->encache(); + } + return $result; + } } diff --git a/classes/Profile.php b/classes/Profile.php index 12ce5d9b6..a32051d07 100644 --- a/classes/Profile.php +++ b/classes/Profile.php @@ -401,10 +401,10 @@ class Profile extends Memcached_DataObject return $profile; } - function getApplications($offset = 0, $limit = null) + function getConnectedApps($offset = 0, $limit = null) { $qry = - 'SELECT a.* ' . + 'SELECT u.* ' . 'FROM oauth_application_user u, oauth_application a ' . 'WHERE u.profile_id = %d ' . 'AND a.id = u.application_id ' . @@ -419,11 +419,11 @@ class Profile extends Memcached_DataObject } } - $application = new Oauth_application(); + $apps = new Oauth_application_user(); - $cnt = $application->query(sprintf($qry, $this->id)); + $cnt = $apps->query(sprintf($qry, $this->id)); - return $application; + return $apps; } function subscriptionCount() diff --git a/classes/statusnet.ini b/classes/statusnet.ini index 3fb8ee208..7aa115fec 100644 --- a/classes/statusnet.ini +++ b/classes/statusnet.ini @@ -393,13 +393,14 @@ name = U profile_id = 129 application_id = 129 access_type = 17 -token = 2 +token = 130 created = 142 modified = 384 [oauth_application_user__keys] profile_id = K application_id = K +token = K [profile] id = 129 -- cgit v1.2.3-54-g00ecf From 3d6a0f730d153378f47805bc6ea8a8d543eb9ab6 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 20 Oct 2010 11:41:04 -0700 Subject: Revert DB change for OAuth. Change compound key for oauth_application_user back to (profile_id, application_id). I think we can get away without a DB change by only issuing one anonymous access token per user. --- classes/Oauth_application_user.php | 2 +- classes/statusnet.ini | 3 +-- db/statusnet.sql | 4 ++-- 3 files changed, 4 insertions(+), 5 deletions(-) (limited to 'classes') diff --git a/classes/Oauth_application_user.php b/classes/Oauth_application_user.php index fcf6553ff..e1b4b8c04 100644 --- a/classes/Oauth_application_user.php +++ b/classes/Oauth_application_user.php @@ -13,7 +13,7 @@ class Oauth_application_user extends Memcached_DataObject public $profile_id; // int(4) primary_key not_null public $application_id; // int(4) primary_key not_null public $access_type; // tinyint(1) - public $token; // varchar(255) primary_key not_null + public $token; // varchar(255) public $created; // datetime not_null public $modified; // timestamp not_null default_CURRENT_TIMESTAMP diff --git a/classes/statusnet.ini b/classes/statusnet.ini index 7aa115fec..3fb8ee208 100644 --- a/classes/statusnet.ini +++ b/classes/statusnet.ini @@ -393,14 +393,13 @@ name = U profile_id = 129 application_id = 129 access_type = 17 -token = 130 +token = 2 created = 142 modified = 384 [oauth_application_user__keys] profile_id = K application_id = K -token = K [profile] id = 129 diff --git a/db/statusnet.sql b/db/statusnet.sql index 4ae7e5684..3f95948e1 100644 --- a/db/statusnet.sql +++ b/db/statusnet.sql @@ -231,10 +231,10 @@ create table oauth_application_user ( profile_id integer not null comment 'user of the application' references profile (id), application_id integer not null comment 'id of the application' references oauth_application (id), access_type tinyint default 0 comment 'access type, bit 1 = read, bit 2 = write', - token varchar(255) not null comment 'request or access token', + token varchar(255) comment 'request or access token', created datetime not null comment 'date this record was created', modified timestamp comment 'date this record was modified', - constraint primary key (profile_id, application_id, token) + constraint primary key (profile_id, application_id) ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; /* These are used by JanRain OpenID library */ -- cgit v1.2.3-54-g00ecf From 8004e2809d98bdd535a3c59bd7d15c3fa2dd7ba9 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Wed, 20 Oct 2010 14:34:25 -0700 Subject: Fix for ticket #2845: singleuser nickname configuration was being overridden by site owner in router setup. I've consolidated the checks for which user to use for single-user mode into User::singleUser(), which now uses the configured nickname by preference, falling back to the site owner if it's unset. This is now called consistently from the places that needed to use the primary user's nickname in routing setup. Setting $config['singleuser']['nickname'] should now work again as expected. --- README | 3 ++- classes/User.php | 29 +++++++++++++++++++++++++++++ lib/action.php | 3 ++- lib/router.php | 12 ++---------- lib/util.php | 3 ++- 5 files changed, 37 insertions(+), 13 deletions(-) (limited to 'classes') diff --git a/README b/README index 26a9fe4ec..43a9bb5e9 100644 --- a/README +++ b/README @@ -1486,7 +1486,8 @@ If an installation has only one user, this can simplify a lot of the interface. It also makes the user's profile the root URL. enabled: Whether to run in "single user mode". Default false. -nickname: nickname of the single user. +nickname: nickname of the single user. If no nickname is specified, + the site owner account will be used (if present). robotstxt --------- diff --git a/classes/User.php b/classes/User.php index e784fd9e9..c68be223d 100644 --- a/classes/User.php +++ b/classes/User.php @@ -875,4 +875,33 @@ class User extends Memcached_DataObject return $owner; } + + /** + * Pull the primary site account to use in single-user mode. + * If a valid user nickname is listed in 'singleuser':'nickname' + * in the config, this will be used; otherwise the site owner + * account is taken by default. + * + * @return User + * @throws ServerException if no valid single user account is present + * @throws ServerException if called when not in single-user mode + */ + static function singleUser() + { + if (common_config('singleuser', 'enabled')) { + $nickname = common_config('singleuser', 'nickname'); + if ($nickname) { + $user = User::staticGet('nickname', $nickname); + } else { + $user = User::siteOwner(); + } + if ($user) { + return $user; + } else { + throw new ServerException(_("No single user defined for single-user mode.")); + } + } else { + throw new ServerException(_('Single-user mode code called when not enabled.')); + } + } } diff --git a/lib/action.php b/lib/action.php index 55ee83bde..e273b5d04 100644 --- a/lib/action.php +++ b/lib/action.php @@ -419,8 +419,9 @@ class Action extends HTMLOutputter // lawsuit 'class' => 'vcard')); if (Event::handle('StartAddressData', array($this))) { if (common_config('singleuser', 'enabled')) { + $user = User::singleUser(); $url = common_local_url('showstream', - array('nickname' => common_config('singleuser', 'nickname'))); + array('nickname' => $user->nickname)); } else { $url = common_local_url('public'); } diff --git a/lib/router.php b/lib/router.php index b1cc8d529..8c682cefa 100644 --- a/lib/router.php +++ b/lib/router.php @@ -701,16 +701,8 @@ class Router if (common_config('singleuser', 'enabled')) { - $user = User::siteOwner(); - - if (!empty($user)) { - $nickname = $user->nickname; - } else { - $nickname = common_config('singleuser', 'nickname'); - if (empty($nickname)) { - throw new ServerException(_("No single user defined for single-user mode.")); - } - } + $user = User::singleUser(); + $nickname = $user->nickname; foreach (array('subscriptions', 'subscribers', 'all', 'foaf', 'xrds', diff --git a/lib/util.php b/lib/util.php index 5a94182bd..86380af28 100644 --- a/lib/util.php +++ b/lib/util.php @@ -974,8 +974,9 @@ function common_tag_link($tag) $canonical = common_canonical_tag($tag); if (common_config('singleuser', 'enabled')) { // regular TagAction isn't set up in 1user mode + $user = User::singleUser(); $url = common_local_url('showstream', - array('nickname' => common_config('singleuser', 'nickname'), + array('nickname' => $user->nickname, 'tag' => $canonical)); } else { $url = common_local_url('tag', array('tag' => $canonical)); -- cgit v1.2.3-54-g00ecf From 28ec9d64632a7a43be9144a474432a3c5b8d6b97 Mon Sep 17 00:00:00 2001 From: Siebrand Mazeland Date: Thu, 21 Oct 2010 01:12:56 +0200 Subject: * translator documentation added. * moved some translator comments that were not directly above the line with the message to the correct location. * i18n for UI text. * superfluous whitespace removed. --- classes/User.php | 4 +++- lib/action.php | 6 +++--- lib/router.php | 8 ++------ 3 files changed, 8 insertions(+), 10 deletions(-) (limited to 'classes') diff --git a/classes/User.php b/classes/User.php index c68be223d..f381ec607 100644 --- a/classes/User.php +++ b/classes/User.php @@ -898,9 +898,11 @@ class User extends Memcached_DataObject if ($user) { return $user; } else { - throw new ServerException(_("No single user defined for single-user mode.")); + // TRANS: Server exception. + throw new ServerException(_('No single user defined for single-user mode.')); } } else { + // TRANS: Server exception. throw new ServerException(_('Single-user mode code called when not enabled.')); } } diff --git a/lib/action.php b/lib/action.php index e273b5d04..3d7d1d808 100644 --- a/lib/action.php +++ b/lib/action.php @@ -527,20 +527,20 @@ class Action extends HTMLOutputter // lawsuit } // TRANS: Tooltip for main menu option "Login" $tooltip = _m('TOOLTIP', 'Login to the site'); - // TRANS: Main menu option when not logged in to log in $this->menuItem(common_local_url('login'), + // TRANS: Main menu option when not logged in to log in _m('MENU', 'Login'), $tooltip, false, 'nav_login'); } // TRANS: Tooltip for main menu option "Help" $tooltip = _m('TOOLTIP', 'Help me!'); - // TRANS: Main menu option for help on the StatusNet site $this->menuItem(common_local_url('doc', array('title' => 'help')), + // TRANS: Main menu option for help on the StatusNet site _m('MENU', 'Help'), $tooltip, false, 'nav_help'); if ($user || !common_config('site', 'private')) { // TRANS: Tooltip for main menu option "Search" $tooltip = _m('TOOLTIP', 'Search for people or text'); - // TRANS: Main menu option when logged in or when the StatusNet instance is not private $this->menuItem(common_local_url('peoplesearch'), + // TRANS: Main menu option when logged in or when the StatusNet instance is not private _m('MENU', 'Search'), $tooltip, false, 'nav_search'); } Event::handle('EndPrimaryNav', array($this)); diff --git a/lib/router.php b/lib/router.php index 8c682cefa..417206e6b 100644 --- a/lib/router.php +++ b/lib/router.php @@ -34,7 +34,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { require_once 'Net/URL/Mapper.php'; class StatusNet_URL_Mapper extends Net_URL_Mapper { - private static $_singleton = null; private function __construct() @@ -71,7 +70,6 @@ class StatusNet_URL_Mapper extends Net_URL_Mapper { * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ - class Router { var $m = null; @@ -692,7 +690,6 @@ class Router $m->connect('admin/snapshot', array('action' => 'snapshotadminpanel')); $m->connect('admin/license', array('action' => 'licenseadminpanel')); - $m->connect('getfile/:filename', array('action' => 'getfile'), array('filename' => '[A-Za-z0-9._-]+')); @@ -757,9 +754,7 @@ class Router $m->connect('', array('action' => 'showstream', 'nickname' => $nickname)); - } else { - $m->connect('', array('action' => 'public')); $m->connect('rss', array('action' => 'publicrss')); $m->connect('featuredrss', array('action' => 'featuredrss')); @@ -840,7 +835,8 @@ class Router } catch (Net_URL_Mapper_InvalidException $e) { common_log(LOG_ERR, "Problem getting route for $path - " . $e->getMessage()); - $cac = new ClientErrorAction("Page not found.", 404); + // TRANS: Client error on action trying to visit a non-existing page. + $cac = new ClientErrorAction(_('Page not found.'), 404); $cac->showPage(); } -- cgit v1.2.3-54-g00ecf From e56385a7bb25336a72c1d37ad43d51ba8e238231 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 20 Oct 2010 17:21:04 -0700 Subject: Use a new table (oauth_token_association) to associate authorized request tokins with OAuth client applications and profiles. --- actions/apioauthaccesstoken.php | 5 +- actions/apioauthauthorize.php | 54 +++++++---- classes/Oauth_token_association.php | 44 +++++++++ classes/statusnet.ini | 12 +++ db/statusnet.sql | 9 ++ lib/apioauthstore.php | 184 ++++++++++++++++++++++++------------ 6 files changed, 230 insertions(+), 78 deletions(-) create mode 100644 classes/Oauth_token_association.php (limited to 'classes') diff --git a/actions/apioauthaccesstoken.php b/actions/apioauthaccesstoken.php index 21e0049ce..d4bd493ee 100644 --- a/actions/apioauthaccesstoken.php +++ b/actions/apioauthaccesstoken.php @@ -78,7 +78,8 @@ class ApiOauthAccessTokenAction extends ApiOauthAction $this->reqToken = $req->get_parameter('oauth_token'); $this->verifier = $req->get_parameter('oauth_verifier'); - $app = $datastore->getAppByRequestToken($this->reqToken); + + $app = $datastore->getAppByRequestToken($this->reqToken); $atok = $server->fetch_access_token($req); } catch (Exception $e) { @@ -106,7 +107,7 @@ class ApiOauthAccessTokenAction extends ApiOauthAction common_log( LOG_INFO, sprintf( - "Issued now access token '%s' for application %d (%s).", + "Issued access token '%s' for application %d (%s).", $atok->key, $app->id, $app->name diff --git a/actions/apioauthauthorize.php b/actions/apioauthauthorize.php index 01cbca18f..51b130296 100644 --- a/actions/apioauthauthorize.php +++ b/actions/apioauthauthorize.php @@ -177,28 +177,24 @@ class ApiOauthAuthorizeAction extends Action $this->serverError($e->getMessage()); } - // associated the authorized req token with the user and the app + // XXX: Make sure we have a oauth_token_association table. The table + // is now in the main schema, but because it is being added with + // a point release, it's unlikely to be there. This code can be + // removed as of 1.0. + $this->ensureOauthTokenAssociationTable(); - $appUser = new Oauth_application_user(); + $tokenAssoc = new Oauth_token_association(); - $appUser->profile_id = $user->id; - $appUser->application_id = $this->app->id; + $tokenAssoc->profile_id = $user->id; + $tokenAssoc->application_id = $this->app->id; + $tokenAssoc->token = $this->oauthTokenParam; + $tokenAssoc->created = common_sql_now(); - // Note: do not copy the access type from the application. - // The access type should always be 0 when the OAuth app - // user record has a request token associated with it. - // Access type gets assigned once an access token has been - // granted. The OAuth app user record then gets updated - // with the new access token and access type. - - $appUser->token = $this->oauthTokenParam; - $appUser->created = common_sql_now(); - - $result = $appUser->insert(); + $result = $tokenAssoc->insert(); if (!$result) { - common_log_db_error($appUser, 'INSERT', __FILE__); - $this->serverError(_('Database error inserting OAuth application user.')); + common_log_db_error($tokenAssoc, 'INSERT', __FILE__); + $this->serverError(_('Database error inserting oauth_token_association.')); } // If we have a callback redirect and provide the token @@ -265,6 +261,30 @@ class ApiOauthAuthorizeAction extends Action } } + // XXX Remove this function when we hit 1.0 + function ensureOauthTokenAssociationTable() + { + $schema = Schema::get(); + + $reqTokenCols = array( + new ColumnDef('profile_id', 'integer', null, true, 'PRI'), + new ColumnDef('application_id', 'integer', null, true, 'PRI'), + new ColumnDef('token', 'varchar', 255, true, 'PRI'), + new ColumnDef('created', 'datetime', null, false), + new ColumnDef( + 'modified', + 'timestamp', + null, + false, + null, + 'CURRENT_TIMESTAMP', + 'on update CURRENT_TIMESTAMP' + ) + ); + + $schema->ensureTable('oauth_token_association', $reqTokenCols); + } + function showForm($error=null) { $this->error = $error; diff --git a/classes/Oauth_token_association.php b/classes/Oauth_token_association.php new file mode 100644 index 000000000..051732712 --- /dev/null +++ b/classes/Oauth_token_association.php @@ -0,0 +1,44 @@ +profile_id = $user->id; + $oau->token = $token; + $oau->limit(1); + + $result = $oau->find(true); + + return empty($result) ? null : $oau; + } + +} + diff --git a/classes/statusnet.ini b/classes/statusnet.ini index 3fb8ee208..ef631e28d 100644 --- a/classes/statusnet.ini +++ b/classes/statusnet.ini @@ -401,6 +401,18 @@ modified = 384 profile_id = K application_id = K +[oauth_token_association] +profile_id = 129 +application_id = 129 +token = 130 +created = 142 +modified = 384 + +[oauth_token_association__keys] +profile_id = K +application_id = K +token = K + [profile] id = 129 nickname = 130 diff --git a/db/statusnet.sql b/db/statusnet.sql index 3f95948e1..ac48e6253 100644 --- a/db/statusnet.sql +++ b/db/statusnet.sql @@ -237,6 +237,15 @@ create table oauth_application_user ( constraint primary key (profile_id, application_id) ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; +create table oauth_token_association ( + profile_id integer not null comment 'user of the application' references profile (id), + application_id integer not null comment 'id of the application' references oauth_application (id), + token varchar(255) comment 'request or access token', + created datetime not null comment 'date this record was created', + modified timestamp comment 'date this record was modified', + constraint primary key (profile_id, application_id, token) +) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; + /* These are used by JanRain OpenID library */ create table oid_associations ( diff --git a/lib/apioauthstore.php b/lib/apioauthstore.php index e30eea129..9a2608263 100644 --- a/lib/apioauthstore.php +++ b/lib/apioauthstore.php @@ -32,24 +32,41 @@ class ApiStatusNetOAuthDataStore extends StatusNetOAuthDataStore // Create an anon consumer and anon application if one // doesn't exist already if ($consumerKey == 'anonymous') { + + common_debug("API OAuth - creating anonymous consumer"); $con = new Consumer(); $con->consumer_key = $consumerKey; $con->consumer_secret = $consumerKey; + $con->created = common_sql_now(); + $result = $con->insert(); if (!$result) { $this->serverError(_("Could not create anonymous consumer.")); } - $app = new OAuth_application(); - $app->consumer_key = $con->consumer_key; - $app->name = 'anonymous'; - - // XXX: allow the user to set the access type when - // authorizing? Currently we default to r+w for anonymous - // OAuth client applications - $app->access_type = 3; // read + write - $id = $app->insert(); - if (!$id) { - $this->serverError(_("Could not create anonymous OAuth application.")); + + $app = Oauth_application::getByConsumerKey('anonymous'); + + if (!$app) { + + common_debug("API OAuth - creating anonymous application"); + $app = new OAuth_application(); + $app->owner = 1; // XXX: What to do here? + $app->consumer_key = $con->consumer_key; + $app->name = 'anonymous'; + $app->icon = 'default-avatar-stream.png'; // XXX: Fix this! + $app->description = "An anonymous application"; + // XXX: allow the user to set the access type when + // authorizing? Currently we default to r+w for anonymous + // OAuth client applications + $app->access_type = 3; // read + write + $app->type = 2; // desktop + $app->created = common_sql_now(); + + $id = $app->insert(); + + if (!$id) { + $this->serverError(_("Could not create anonymous OAuth application.")); + } } } else { return null; @@ -64,10 +81,12 @@ class ApiStatusNetOAuthDataStore extends StatusNetOAuthDataStore function getAppByRequestToken($token_key) { - // Look up the full req tokenx - $req_token = $this->lookup_token(null, - 'request', - $token_key); + // Look up the full req token + $req_token = $this->lookup_token( + null, + 'request', + $token_key + ); if (empty($req_token)) { common_debug("couldn't get request token from oauth datastore"); @@ -85,7 +104,6 @@ class ApiStatusNetOAuthDataStore extends StatusNetOAuthDataStore } // Look up the app - $app = new Oauth_application(); $app->consumer_key = $token->consumer_key; $result = $app->find(true); @@ -102,12 +120,12 @@ class ApiStatusNetOAuthDataStore extends StatusNetOAuthDataStore { common_debug( sprintf( - "%s - New access token from request token %s, consumer %s and verifier %s ", - __FILE__, + "New access token from request token %s, consumer %s and verifier %s ", $token, $consumer, $verifier - ) + ), + __FILE__ ); $rt = new Token(); @@ -121,73 +139,121 @@ class ApiStatusNetOAuthDataStore extends StatusNetOAuthDataStore if ($rt->find(true) && $rt->state == 1 && $rt->verifier == $verifier) { // authorized - common_debug('request token found.'); + common_debug('Request token found.', __FILE__); + + // find the app and profile associated with this token - // find the associated user of the app + $tokenAssoc = OAuth_token_association::staticGet('token', $rt->tok); + + if (!$tokenAssoc) { + throw new Exception( + _('Could not find a profile and application associated with the request token.') + ); + } + + // check to see if we have previously issued an access token for this application + // and profile $appUser = new Oauth_application_user(); $appUser->application_id = $app->id; - $appUser->token = $rt->tok; + $appUser->profile_id = $tokenAssoc->profile_id; $result = $appUser->find(true); if (!empty($result)) { - common_debug("Ouath app user found."); - } else { - common_debug("Oauth app user not found. app id $app->id token $rt->tok"); - return null; - } - // go ahead and make the access token + common_log(LOG_INFO, + sprintf( + "Existing access token found for application %s, profile %s.", + $app->id, + $tokenAssoc->profile_id + ) + ); - $at = new Token(); - $at->consumer_key = $consumer->key; - $at->tok = common_good_rand(16); - $at->secret = common_good_rand(16); - $at->type = 1; // access - $at->verifier = $verifier; - $at->verified_callback = $rt->verified_callback; // 1.0a - $at->created = DB_DataObject_Cast::dateTime(); + $at = new Token(); - if (!$at->insert()) { - $e = $at->_lastError; - common_debug('access token "'.$at->tok.'" not inserted: "'.$e->message.'"', __FILE__); - return null; - } else { - common_debug('access token "'.$at->tok.'" inserted', __FILE__); - // burn the old one - $orig_rt = clone($rt); - $rt->state = 2; // used - if (!$rt->update($orig_rt)) { - return null; + // fetch the full access token + $at->consumer_key = $consumer->key; + $at->tok = $appUser->token; + + $result = $at->find(true); + + if (!$result) { + throw new Exception( + _('Could not issue access token.') + ); } - common_debug('request token "'.$rt->tok.'" updated', __FILE__); - // update the token from req to access for the user + // Yay, we can re-issue the access token + return new OAuthToken($at->tok, $at->secret); - $orig = clone($appUser); + } else { - $appUser->token = $at->tok; + common_log(LOG_INFO, + sprintf( + "Creating new access token for application %s, profile %s.", + $app->id, + $tokenAssoc->profile_id + ) + ); + + // make a brand new access token + $at = new Token(); + + $at->consumer_key = $consumer->key; + $at->tok = common_good_rand(16); + $at->secret = common_good_rand(16); + $at->type = 1; // access + $at->verifier = $verifier; + $at->verified_callback = $rt->verified_callback; // 1.0a + $at->created = common_sql_now(); + + if (!$at->insert()) { + $e = $at->_lastError; + common_debug('access token "' . $at->tok . '" not inserted: "' . $e->message . '"', __FILE__); + return null; + } else { + common_debug('access token "' . $at->tok . '" inserted', __FILE__); + // burn the old one + $orig_rt = clone($rt); + $rt->state = 2; // used + if (!$rt->update($orig_rt)) { + return null; + } + common_debug('request token "' . $rt->tok . '" updated', __FILE__); + } - // It's at this point that we change the access type - // to whatever the application's access is. Request - // tokens should always have an access type of 0, and - // therefore be unuseable for making requests for - // protected resources. + // insert a new Oauth_application_user record w/access token + $appUser = new Oauth_application_user(); - $appUser->access_type = $app->access_type; + $appUser->profile_id = $tokenAssoc->profile_id;; + $appUser->application_id = $app->id; + $appUser->access_type = $app->access_type; + $appUser->token = $at->tok; + $appUser->created = common_sql_now(); - $result = $appUser->updateKeys($orig); + $result = $appUser->insert(); if (!$result) { - throw new Exception('Couldn\'t update OAuth app user.'); + common_log_db_error($appUser, 'INSERT', __FILE__); + $this->serverError(_('Database error inserting OAuth application user.')); } // Okay, good return new OAuthToken($at->tok, $at->secret); } + } else { + + // the token was not authorized or not verfied + common_log( + LOG_INFO, + sprintf( + "API OAuth - Attempt to exchange unauthorized or unverified request token %s for an access token.", + $rt->tok + ) + ); return null; } } -- cgit v1.2.3-54-g00ecf From fb12094f616c52674b9a0a719fd78469ae60a6e6 Mon Sep 17 00:00:00 2001 From: Siebrand Mazeland Date: Thu, 21 Oct 2010 03:10:46 +0200 Subject: i18n/L10n updates, translator docs updated, superfluous whitespace removed. --- actions/apioauthauthorize.php | 9 ++------- classes/Oauth_token_association.php | 2 -- lib/apioauthstore.php | 6 ++++-- lib/dberroraction.php | 1 - lib/feed.php | 1 - lib/feedlist.php | 1 - lib/groupsbymemberssection.php | 2 +- lib/groupsbypostssection.php | 2 +- lib/groupsection.php | 1 - lib/grouptagcloudsection.php | 3 ++- lib/xmppmanager.php | 15 +++++++++------ lib/xmppoutqueuehandler.php | 1 - 12 files changed, 19 insertions(+), 25 deletions(-) (limited to 'classes') diff --git a/actions/apioauthauthorize.php b/actions/apioauthauthorize.php index ca32c8540..013cca029 100644 --- a/actions/apioauthauthorize.php +++ b/actions/apioauthauthorize.php @@ -92,7 +92,6 @@ class ApiOauthAuthorizeAction extends Action * * @return void */ - function handle($args) { parent::handle($args); @@ -120,7 +119,7 @@ class ApiOauthAuthorizeAction extends Action // Check to make sure we haven't already authorized the token if ($this->reqToken->state != 0) { // TRANS: Client error given when an invalid request token was passed to the OAuth API. - $this->clientError(_("Invalid request token.")); + $this->clientError(_('Invalid request token.')); } } } @@ -202,6 +201,7 @@ class ApiOauthAuthorizeAction extends Action if (!$result) { common_log_db_error($tokenAssoc, 'INSERT', __FILE__); + // TRANS: Server error displayed when a database action fails. $this->serverError(_('Database error inserting oauth_token_association.')); } @@ -251,16 +251,13 @@ class ApiOauthAuthorizeAction extends Action // Otherwise, inform the user that the rt was authorized $this->showAuthorized(); - } else if ($this->arg('cancel')) { - try { $this->store->revoke_token($this->oauthTokenParam, 0); $this->showCanceled(); } catch (Exception $e) { $this->ServerError($e->getMessage()); } - } else { // TRANS: Client error given on when invalid data was passed through a form in the OAuth API. $this->clientError(_('Unexpected form submission.')); @@ -310,7 +307,6 @@ class ApiOauthAuthorizeAction extends Action * * @return string title of the page */ - function title() { // TRANS: Title for a page where a user can confirm/deny account access by an external application. @@ -322,7 +318,6 @@ class ApiOauthAuthorizeAction extends Action * * @return void */ - function showContent() { $this->elementStart('form', array('method' => 'post', diff --git a/classes/Oauth_token_association.php b/classes/Oauth_token_association.php index 051732712..66be22b5d 100644 --- a/classes/Oauth_token_association.php +++ b/classes/Oauth_token_association.php @@ -39,6 +39,4 @@ class Oauth_token_association extends Memcached_DataObject return empty($result) ? null : $oau; } - } - diff --git a/lib/apioauthstore.php b/lib/apioauthstore.php index 6b9b97756..a5e807d03 100644 --- a/lib/apioauthstore.php +++ b/lib/apioauthstore.php @@ -48,7 +48,6 @@ class ApiStatusNetOAuthDataStore extends StatusNetOAuthDataStore $app = Oauth_application::getByConsumerKey('anonymous'); if (!$app) { - common_debug("API OAuth - creating anonymous application"); $app = new OAuth_application(); $app->owner = 1; // XXX: What to do here? @@ -66,7 +65,7 @@ class ApiStatusNetOAuthDataStore extends StatusNetOAuthDataStore $id = $app->insert(); if (!$id) { - // TRANS: Server error displayed when trying to create an anynymous OAuth application. + // TRANS: Server error displayed when trying to create an anynymous OAuth application. $this->serverError(_("Could not create anonymous OAuth application.")); } } @@ -149,6 +148,7 @@ class ApiStatusNetOAuthDataStore extends StatusNetOAuthDataStore if (!$tokenAssoc) { throw new Exception( + // TRANS: Exception thrown when no token association could be found. _('Could not find a profile and application associated with the request token.') ); } @@ -183,6 +183,7 @@ class ApiStatusNetOAuthDataStore extends StatusNetOAuthDataStore if (!$result) { throw new Exception( + // TRANS: Exception thrown when no access token can be issued. _('Could not issue access token.') ); } @@ -239,6 +240,7 @@ class ApiStatusNetOAuthDataStore extends StatusNetOAuthDataStore if (!$result) { common_log_db_error($appUser, 'INSERT', __FILE__); + // TRANS: Server error displayed when a database error occurs. $this->serverError(_('Database error inserting OAuth application user.')); } diff --git a/lib/dberroraction.php b/lib/dberroraction.php index 2cb66a022..0a6fce100 100644 --- a/lib/dberroraction.php +++ b/lib/dberroraction.php @@ -47,7 +47,6 @@ require_once INSTALLDIR.'/lib/servererroraction.php'; * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 * @link http://status.net/ */ - class DBErrorAction extends ServerErrorAction { function __construct($message='Error', $code=500) diff --git a/lib/feed.php b/lib/feed.php index e9fb6fdff..590265367 100644 --- a/lib/feed.php +++ b/lib/feed.php @@ -43,7 +43,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ - class Feed { const RSS1 = 1; diff --git a/lib/feedlist.php b/lib/feedlist.php index 4aacf0b3d..076576028 100644 --- a/lib/feedlist.php +++ b/lib/feedlist.php @@ -46,7 +46,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { * * @see Action::showExportList() */ - class FeedList extends Widget { var $action = null; diff --git a/lib/groupsbymemberssection.php b/lib/groupsbymemberssection.php index 19b35eddb..5cf1a563c 100644 --- a/lib/groupsbymemberssection.php +++ b/lib/groupsbymemberssection.php @@ -40,7 +40,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ - class GroupsByMembersSection extends GroupSection { function getGroups() @@ -68,6 +67,7 @@ class GroupsByMembersSection extends GroupSection function title() { + // TRANS: Title for groups with the most members section. return _('Groups with most members'); } diff --git a/lib/groupsbypostssection.php b/lib/groupsbypostssection.php index 45d49aba6..50d60e87c 100644 --- a/lib/groupsbypostssection.php +++ b/lib/groupsbypostssection.php @@ -40,7 +40,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ - class GroupsByPostsSection extends GroupSection { function getGroups() @@ -68,6 +67,7 @@ class GroupsByPostsSection extends GroupSection function title() { + // TRANS: Title for groups with the most posts section. return _('Groups with most posts'); } diff --git a/lib/groupsection.php b/lib/groupsection.php index 3b0b3029d..019b13135 100644 --- a/lib/groupsection.php +++ b/lib/groupsection.php @@ -45,7 +45,6 @@ define('GROUPS_PER_SECTION', 6); * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ - class GroupSection extends Section { function showContent() diff --git a/lib/grouptagcloudsection.php b/lib/grouptagcloudsection.php index f1106cc7b..5b914c007 100644 --- a/lib/grouptagcloudsection.php +++ b/lib/grouptagcloudsection.php @@ -40,7 +40,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ - class GroupTagCloudSection extends TagCloudSection { var $group = null; @@ -53,6 +52,8 @@ class GroupTagCloudSection extends TagCloudSection function title() { + // TRANS: Title for group tag cloud section. + // TRANS: %s is a group name. return sprintf(_('Tags in %s group\'s notices'), $this->group->nickname); } diff --git a/lib/xmppmanager.php b/lib/xmppmanager.php index 829eaa36c..7acd7663a 100644 --- a/lib/xmppmanager.php +++ b/lib/xmppmanager.php @@ -30,7 +30,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } * In a multi-site queuedaemon.php run, one connection will be instantiated * for each site being handled by the current process that has XMPP enabled. */ - class XmppManager extends IoManager { protected $site = null; @@ -102,6 +101,7 @@ class XmppManager extends IoManager $this->conn->addEventHandler('reconnect', 'handle_reconnect', $this); $this->conn->setReconnectTimeout(600); + // @todo Needs i18n? jabber_send_presence("Send me a message to post a notice", 'available', null, 'available', 100); return !is_null($this->conn); @@ -281,9 +281,9 @@ class XmppManager extends IoManager $_cur = $user; if (!$user) { - $this->from_site($from, 'Unknown user; go to ' . - common_local_url('imsettings') . - ' to add your address to your account'); + // TRANS: %s is the URL to the StatusNet site's Instant Messaging settings. + $this->from_site($from, sprintf(_('Unknown user. Go to %s ' . + 'to add your address to your account'),common_local_url('imsettings'))); $this->log(LOG_WARNING, 'Message from unknown user ' . $from); return; } @@ -314,7 +314,6 @@ class XmppManager extends IoManager unset($pl); } - function is_self($from) { return preg_match('/^'.strtolower(jabber_daemon_address()).'/', strtolower($from)); @@ -400,7 +399,11 @@ class XmppManager extends IoManager $content_shortened = common_shorten_links($body); if (Notice::contentTooLong($content_shortened)) { $from = jabber_normalize_jid($pl['from']); - $this->from_site($from, sprintf(_('Message too long - maximum is %1$d characters, you sent %2$d.'), + // TRANS: Response to XMPP source when it sent too long a message. + // TRANS: %1$d the maximum number of allowed characters (used for plural), %2$d is the sent number. + $this->from_site($from, sprintf(_m('Message too long. Maximum is %1$d character, you sent %2$d.', + 'Message too long. Maximum is %1$d characters, you sent %2$d.', + Notice::maxContent()), Notice::maxContent(), mb_strlen($content_shortened))); return; diff --git a/lib/xmppoutqueuehandler.php b/lib/xmppoutqueuehandler.php index 2afa260f1..a4c9bbc4d 100644 --- a/lib/xmppoutqueuehandler.php +++ b/lib/xmppoutqueuehandler.php @@ -52,4 +52,3 @@ class XmppOutQueueHandler extends QueueHandler return $ok; } } - -- cgit v1.2.3-54-g00ecf From 8ac8f3d2dc95a437dea7dec2d26f09a364734a9b Mon Sep 17 00:00:00 2001 From: James Walker Date: Thu, 21 Oct 2010 12:20:14 -0400 Subject: Memcache::set() 3rd param should be flags (4th is expire). This throws a "2 lowest bytes reserved" error in Memcache > 3.0.3 --- classes/Status_network_tag.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'classes') diff --git a/classes/Status_network_tag.php b/classes/Status_network_tag.php index a5893c114..3398ac8c8 100644 --- a/classes/Status_network_tag.php +++ b/classes/Status_network_tag.php @@ -99,7 +99,7 @@ class Status_network_tag extends Safe_DataObject if (Status_network::$cache) { $packed = implode('|', $result); - Status_network::$cache->set($key, $packed, 3600); + Status_network::$cache->set($key, $packed, 0, 3600); } return $result; -- cgit v1.2.3-54-g00ecf From 1d85bfece1ac3d6de3b4c350cbb617982e9d8638 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Fri, 22 Oct 2010 10:31:50 -0400 Subject: New events when granting and revoking roles Four new events for when roles are granted or revoked. --- EVENTS.txt | 16 +++++++++++++++ classes/Profile.php | 57 +++++++++++++++++++++++++++++++---------------------- 2 files changed, 49 insertions(+), 24 deletions(-) (limited to 'classes') diff --git a/EVENTS.txt b/EVENTS.txt index e5cafa857..8e730945a 100644 --- a/EVENTS.txt +++ b/EVENTS.txt @@ -1142,3 +1142,19 @@ StartShowNoticeForm: before showing the notice form (before
) EndShowNoticeForm: after showing the notice form (after ) - $action: action being executed + +StartGrantRole: when a role is being assigned +- $profile: profile that will have the role +- $role: string name of the role + +EndGrantRole: when a role has been successfully assigned +- $profile: profile that will have the role +- $role: string name of the role + +StartRevokeRole: when a role is being revoked +- $profile: profile that will lose the role +- $role: string name of the role + +EndRevokeRole: when a role has been revoked +- $profile: profile that lost the role +- $role: string name of the role diff --git a/classes/Profile.php b/classes/Profile.php index a32051d07..cb5ca54b0 100644 --- a/classes/Profile.php +++ b/classes/Profile.php @@ -758,43 +758,52 @@ class Profile extends Memcached_DataObject function grantRole($name) { - $role = new Profile_role(); + if (Event::handle('StartGrantRole', array($this, $name))) { - $role->profile_id = $this->id; - $role->role = $name; - $role->created = common_sql_now(); + $role = new Profile_role(); - $result = $role->insert(); + $role->profile_id = $this->id; + $role->role = $name; + $role->created = common_sql_now(); - if (!$result) { - common_log_db_error($role, 'INSERT', __FILE__); - return false; + $result = $role->insert(); + + if (!$result) { + throw new Exception("Can't save role '$name' for profile '{$this->id}'"); + } + + Event::handle('EndGrantRole', array($this, $name)); } - return true; + return $result; } function revokeRole($name) { - $role = Profile_role::pkeyGet(array('profile_id' => $this->id, - 'role' => $name)); + if (Event::handle('StartRevokeRole', array($this, $name))) { - if (empty($role)) { - // TRANS: Exception thrown when trying to revoke an existing role for a user that does not exist. - // TRANS: %1$s is the role name, %2$s is the user ID (number). - throw new Exception(sprintf(_('Cannot revoke role "%1$s" for user #%2$d; does not exist.'),$name, $this->id)); - } + $role = Profile_role::pkeyGet(array('profile_id' => $this->id, + 'role' => $name)); - $result = $role->delete(); + if (empty($role)) { + // TRANS: Exception thrown when trying to revoke an existing role for a user that does not exist. + // TRANS: %1$s is the role name, %2$s is the user ID (number). + throw new Exception(sprintf(_('Cannot revoke role "%1$s" for user #%2$d; does not exist.'),$name, $this->id)); + } - if (!$result) { - common_log_db_error($role, 'DELETE', __FILE__); - // TRANS: Exception thrown when trying to revoke a role for a user with a failing database query. - // TRANS: %1$s is the role name, %2$s is the user ID (number). - throw new Exception(sprintf(_('Cannot revoke role "%1$s" for user #%2$d; database error.'),$name, $this->id)); - } + $result = $role->delete(); - return true; + if (!$result) { + common_log_db_error($role, 'DELETE', __FILE__); + // TRANS: Exception thrown when trying to revoke a role for a user with a failing database query. + // TRANS: %1$s is the role name, %2$s is the user ID (number). + throw new Exception(sprintf(_('Cannot revoke role "%1$s" for user #%2$d; database error.'),$name, $this->id)); + } + + Event::handle('EndRevokeRole', array($this, $name)); + + return true; + } } function isSandboxed() -- cgit v1.2.3-54-g00ecf From 0b6cc7c33d5239bbc9f01c00d3fb8c00a3d6e4c7 Mon Sep 17 00:00:00 2001 From: Siebrand Mazeland Date: Sat, 23 Oct 2010 19:20:51 +0200 Subject: * translator documentation added. * superfluous whitespace removed. --- actions/apioauthauthorize.php | 2 +- actions/oauthappssettings.php | 6 +++++- classes/Status_network_tag.php | 1 - 3 files changed, 6 insertions(+), 3 deletions(-) (limited to 'classes') diff --git a/actions/apioauthauthorize.php b/actions/apioauthauthorize.php index b83582702..f2f1071d9 100644 --- a/actions/apioauthauthorize.php +++ b/actions/apioauthauthorize.php @@ -579,7 +579,7 @@ class ApiOauthAuthorizeAction extends Action $title = sprintf( // TRANS: Header of user notification after authorising an application access to a profile. // TRANS: %s is the authorised application name. - _("You have successfully authorized %s."), + _('You have successfully authorized %s.'), $this->app->name ); diff --git a/actions/oauthappssettings.php b/actions/oauthappssettings.php index e75f014ab..c98c90dbf 100644 --- a/actions/oauthappssettings.php +++ b/actions/oauthappssettings.php @@ -56,6 +56,7 @@ class OauthappssettingsAction extends SettingsAction $this->page = ($this->arg('page')) ? ($this->arg('page') + 0) : 1; if (!common_logged_in()) { + // TRANS: Message displayed to an anonymous user trying to view OAuth application list. $this->clientError(_('You must be logged in to list your applications.')); return false; } @@ -71,6 +72,7 @@ class OauthappssettingsAction extends SettingsAction function title() { + // TRANS: Page title for OAuth applications return _('OAuth applications'); } @@ -82,6 +84,7 @@ class OauthappssettingsAction extends SettingsAction function getInstructions() { + // TRANS: Page instructions for OAuth applications return _('Applications you have registered'); } @@ -120,6 +123,7 @@ class OauthappssettingsAction extends SettingsAction array('href' => common_local_url('newapplication'), 'class' => 'more' ), + // TRANS: Link description to add a new OAuth application. 'Register a new application'); $this->elementEnd('p'); @@ -133,6 +137,7 @@ class OauthappssettingsAction extends SettingsAction function showEmptyListMessage() { + // TRANS: Empty list message on page with OAuth applications. $message = sprintf(_('You have not registered any applications yet.')); $this->elementStart('div', 'guide'); @@ -163,5 +168,4 @@ class OauthappssettingsAction extends SettingsAction } } - } diff --git a/classes/Status_network_tag.php b/classes/Status_network_tag.php index 3398ac8c8..2273ecb2e 100644 --- a/classes/Status_network_tag.php +++ b/classes/Status_network_tag.php @@ -43,7 +43,6 @@ class Status_network_tag extends Safe_DataObject $this->_connect(); } - /* Static get */ function staticGet($k,$v=null) { -- cgit v1.2.3-54-g00ecf From 968f9b0513f1a2329ad3d9815303b32f94487764 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 25 Oct 2010 11:08:53 -0400 Subject: change max_id from < to <= --- classes/Profile.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'classes') diff --git a/classes/Profile.php b/classes/Profile.php index cb5ca54b0..a359a02d9 100644 --- a/classes/Profile.php +++ b/classes/Profile.php @@ -199,7 +199,7 @@ class Profile extends Memcached_DataObject } if ($max_id != 0) { - $query .= " and id < $max_id"; + $query .= " and id <= $max_id"; } $query .= ' order by id DESC'; -- cgit v1.2.3-54-g00ecf From aef88c7ceeb219c12d4ebce65b6f1fbccbc1458a Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 25 Oct 2010 11:18:49 -0400 Subject: max_id is inclusive --- classes/Notice_tag.php | 2 +- classes/Profile.php | 2 +- classes/Reply.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'classes') diff --git a/classes/Notice_tag.php b/classes/Notice_tag.php index a5d0716a7..6eada7022 100644 --- a/classes/Notice_tag.php +++ b/classes/Notice_tag.php @@ -60,7 +60,7 @@ class Notice_tag extends Memcached_DataObject } if ($max_id != 0) { - $nt->whereAdd('notice_id < ' . $max_id); + $nt->whereAdd('notice_id <= ' . $max_id); } $nt->orderBy('notice_id DESC'); diff --git a/classes/Profile.php b/classes/Profile.php index a359a02d9..37d2c571f 100644 --- a/classes/Profile.php +++ b/classes/Profile.php @@ -240,7 +240,7 @@ class Profile extends Memcached_DataObject } if ($max_id != 0) { - $query .= " and id < $max_id"; + $query .= " and id <= $max_id"; } $query .= ' order by id DESC'; diff --git a/classes/Reply.php b/classes/Reply.php index dc6296bda..da8a4f685 100644 --- a/classes/Reply.php +++ b/classes/Reply.php @@ -55,7 +55,7 @@ class Reply extends Memcached_DataObject } if ($max_id != 0) { - $reply->whereAdd('notice_id < ' . $max_id); + $reply->whereAdd('notice_id <= ' . $max_id); } $reply->orderBy('notice_id DESC'); -- cgit v1.2.3-54-g00ecf