Merge remote branch 'statusnet/1.0.x' into irc-plugin

This commit is contained in:
Luke Fitzgerald 2010-08-07 13:25:56 -07:00
commit bee5084072
179 changed files with 20439 additions and 7197 deletions

View File

@ -836,3 +836,230 @@ EndDeleteUser: handling the post for deleting a user
- $action: action being shown - $action: action being shown
- $user: user being deleted - $user: user being deleted
StartActivityStart: starting the output for a notice activity <event>
- &$notice: notice being output
- &$xs: XMLStringer for output
- &$attrs: <entry> attributes (mostly namespace declarations, if any)
EndActivityStart: end the opening tag for an activity <event>
- &$notice: notice being output
- &$xs: XMLStringer for output
- $attrs: <entry> attributes (mostly namespace declarations, if any)
StartActivitySource: before outputting the <source> element for a notice activity
- &$notice: notice being output
- &$xs: XMLStringer for output
EndActivitySource: after outputting the <source> element for a notice activity
- &$notice: notice being output
- &$xs: XMLStringer for output
StartActivityTitle: before outputting notice activity title
- &$notice: notice being output
- &$xs: XMLStringer for output
- &$title: title of the notice, mutable
EndActivityTitle: after outputting notice activity title
- $notice: notice being output
- &$xs: XMLStringer for output
- $title: title of the notice
StartActivityAuthor: before outputting atom author
- &$notice: notice being output
- &$xs: XMLStringer for output
- &$atomAuthor: string for XML representing atom author
EndActivityAuthor: after outputting atom author
- &$notice: notice being output
- &$xs: XMLStringer for output
- &$atomAuthor: string for XML representing atom author
StartActivityActor: before outputting activity actor element for a notice activity entry
- &$notice: notice being output
- &$xs: XMLStringer for output
- &$actor: string for XML representing activity actor
EndActivityActor: after outputting activity actor element for a notice activity entry
- &$notice: notice being output
- &$xs: XMLStringer for output
- &$actor: string for XML representing activity actor
StartActivityLink: before outputting activity HTML link element for a notice activity entry
- &$notice: notice being output
- &$xs: XMLStringer for output
- &$url: URL for activity HTML link element for a notice activity entry
EndActivityLink: before outputting activity HTML link element for a notice activity entry
- &$notice: notice being output
- &$xs: XMLStringer for output
- $url: URL for activity HTML link element for a notice activity entry
StartActivityId: before outputting atom:id element for a notice activity entry
- &$notice: notice being output
- &$xs: XMLStringer for output
- &$id: atom:id (notice URI by default)
EndActivityId: after outputting atom:id element for a notice activity entry
- &$notice: notice being output
- &$xs: XMLStringer for output
- $id: atom:id (notice URI by default)
StartActivityPublished: before outputting atom:published element for a notice activity entry
- &$notice: notice being output
- &$xs: XMLStringer for output
- &$published: atom:published value (notice created by default)
EndActivityPublished: before outputting atom:published element for a notice activity entry
- &$notice: notice being output
- &$xs: XMLStringer for output
- $published: atom:published value (notice created by default)
StartActivityUpdated: before outputting atom:updated element for a notice activity entry
- &$notice: notice being output
- &$xs: XMLStringer for output
- &$updated: atom:updated value (same as atom:published by default)
EndActivityUpdated: after outputting atom:updated element for a notice activity entry
- &$notice: notice being output
- &$xs: XMLStringer for output
- $updated: atom:updated value (same as atom:published by default)
StartActivityContent: before outputting atom:content element for a notice activity entry
- &$notice: notice being output
- &$xs: XMLStringer for output
- &$content: atom:content value (notice rendered HTML by default)
EndActivityContent: after outputting atom:content element for a notice activity entry
- &$notice: notice being output
- &$xs: XMLStringer for output
- $content: atom:content value (notice rendered HTML by default)
StartActivityVerb: before outputting activity:verb element for a notice activity entry
- &$notice: notice being output
- &$xs: XMLStringer for output
- &$verb: activity:verb URI ('http://activitystrea.ms/schema/1.0/post' by default)
EndActivityVerb: after outputting activity:verb element for a notice activity entry
- &$notice: notice being output
- &$xs: XMLStringer for output
- $verb: activity:verb URI ('http://activitystrea.ms/schema/1.0/post' by default)
StartActivityDefaultObjectType: before outputting activity:object-type element for a notice activity entry
- &$notice: notice being output
- &$xs: XMLStringer for output
- &$type: activity:object-type URI for default object ('http://activitystrea.ms/schema/1.0/note' by default)
EndActivityDefaultObjectType: after outputting activity:verb element for a notice activity entry
- &$notice: notice being output
- &$xs: XMLStringer for output
- $type: activity:object-type URI for default object ('http://activitystrea.ms/schema/1.0/note' by default)
StartActivityObjects: before outputting activity:object elements for a notice activity entry
- &$notice: notice being output
- &$xs: XMLStringer for output
- &$objects: array of ActivityObject objects to output (empty by default)
EndActivityObjects: after outputting activity:object elements for a notice activity entry
- &$notice: notice being output
- &$xs: XMLStringer for output
- $objects: array of ActivityObject objects to output (empty by default)
StartActivityNoticeInfo: before outputting statusnet:notice-info element for a notice activity entry
- &$notice: notice being output
- &$xs: XMLStringer for output
- &$noticeInfoAttr: array of attributes for notice info element
EndActivityNoticeInfo: after outputting statusnet:notice-info element for a notice activity entry
- &$notice: notice being output
- &$xs: XMLStringer for output
- $noticeInfoAttr: array of attributes for notice info element
StartActivityInReplyTo: before outputting thr:in-reply-to element for a notice activity entry
- &$notice: notice being output
- &$xs: XMLStringer for output
- &$replyNotice: Notice object the main notice is in-reply-to
EndActivityInReplyTo: after outputting thr:in-reply-to element for a notice activity entry
- &$notice: notice being output
- &$xs: XMLStringer for output
- $replyNotice: Notice object the main notice is in-reply-to
StartActivityConversation: before outputting ostatus:conversation link element for a notice activity entry
- &$notice: notice being output
- &$xs: XMLStringer for output
- &$conv: Conversation object
EndActivityConversation: after outputting ostatus:conversation link element for a notice activity entry
- &$notice: notice being output
- &$xs: XMLStringer for output
- $conv: Conversation object
StartActivityAttentionProfiles: before outputting ostatus:attention link element for people in a notice activity entry
- &$notice: notice being output
- &$xs: XMLStringer for output
- &$replyProfiles: array of profiles of people being replied to
EndActivityAttentionProfiles: after outputting ostatus:attention link element for people in a notice activity entry
- &$notice: notice being output
- &$xs: XMLStringer for output
- $replyProfiles: array of Profile object of people being replied to
StartActivityAttentionGroups: before outputting ostatus:attention link element for groups in a notice activity entry
- &$notice: notice being output
- &$xs: XMLStringer for output
- &$groups: array of Group objects of groups being addressed
EndActivityAttentionGroups: after outputting ostatus:attention link element for groups in a notice activity entry
- &$notice: notice being output
- &$xs: XMLStringer for output
- $groups: array of Group objects of groups being addressed
StartActivityForward: before outputting ostatus:forward link element in a notice activity entry
- &$notice: notice being output
- &$xs: XMLStringer for output
- &$repeat: Notice that was repeated
EndActivityForward: after outputting ostatus:forward link element in a notice activity entry
- &$notice: notice being output
- &$xs: XMLStringer for output
- $repeat: Notice that was repeated
StartActivityCategories: before outputting atom:category elements in a notice activity entry
- &$notice: notice being output
- &$xs: XMLStringer for output
- &$tags: array of strings for tags on the notice (used for categories)
EndActivityCategories: after outputting atom:category elements in a notice activity entry
- &$notice: notice being output
- &$xs: XMLStringer for output
- $tags: array of strings for tags on the notice (used for categories)
StartActivityEnclosures: before outputting enclosure link elements in a notice activity entry
- &$notice: notice being output
- &$xs: XMLStringer for output
- &$enclosures: array of enclosure objects (see File::getEnclosure() for details)
EndActivityEnclosures: after outputting enclosure link elements in a notice activity entry
- &$notice: notice being output
- &$xs: XMLStringer for output
- $enclosures: array of enclosure objects (see File::getEnclosure() for details)
StartActivityGeo: before outputting geo:rss element in a notice activity entry
- &$notice: notice being output
- &$xs: XMLStringer for output
- &$lat: latitude
- &$lon: longitude
EndActivityGeo: after outputting geo:rss element in a notice activity entry
- &$notice: notice being output
- &$xs: XMLStringer for output
- $lat: latitude
- $lon: longitude
StartActivityEnd: before the closing </entry> in a notice activity entry (last chance for data!)
- &$notice: notice being output
- &$xs: XMLStringer for output
EndActivityEnd: after the closing </entry> in a notice activity entry
- &$notice: notice being output
- &$xs: XMLStringer for output

53
README
View File

@ -2,8 +2,8 @@
README README
------ ------
StatusNet 0.9.2 ("King of Birds") StatusNet 0.9.3 ("Half a World Away")
3 May 2010 29 June 2010
This is the README file for StatusNet, the Open Source microblogging This is the README file for StatusNet, the Open Source microblogging
platform. It includes installation instructions, descriptions of platform. It includes installation instructions, descriptions of
@ -77,40 +77,27 @@ for additional terms.
New this version New this version
================ ================
This is a minor bug and feature release since version 0.9.1 released 28 This is a minor bug and feature release since version 0.9.2 released on
March 2010. 4 May 2010.
Because of fixes to OStatus bugs, it is highly recommended that all For best compatibility with client software and site federation, and a lot of
public sites upgrade to the new version immediately. bug fixes, it is highly recommended that all public sites upgrade to the new
version.
Notable changes this version: Notable changes this version:
- Installer no longer fails with a PHP fatal error when trying to set up the - Enhanced API output to aid StatusNet-specific clients
subscription to update@status.net - Many updates to user interface translation from TranslateWiki
- Fixed email notifications for @-replies that come in via OStatus - OStatus now works subscribing to SSL-protected sites by default
- OStatus related Fixes to the cloudy theme - OpenID now works on PHP 5.3, supports closer site integration.
- Pass geo locations over Twitter bridge (will only be used if enabled on the - Numerous API and FOAF output fixes.
Twitter side) - Fixes to Facebook integration for FB API behavior changes
- scripts/showplugins.php - script to dump the list of activated plugins and - PostgreSQL support updates
their settings - Initial version of a custom theme uploader (disabled by default)
- scripts/fixup_blocks.php - script to finds any stray subscriptions in - LDAP auth plugins cleanup
violation of blocks, and removes them - Many other bugfixes
- Allow blocking someone who's not currently subscribed to you (prevents
seeing @-replies from them, or them subbing to you in future)
- Default 2-second timeout on Geonames web service lookups
- Improved localization for plugins
- New anti-spam measures: added nofollow rels to group members list,
subscribers list
- Shared cache key option for Geonames plugin (lets multi-instance sites
share their cached geoname lookups)
- Stability fixes to the TwitterStatusFetcher
- If user allows location sharing but turned off browser location use profile
location
- Improved group listing via the API
- Improved FOAF output
- Several other bugfixes
A full changelog is available at http://status.net/wiki/StatusNet_0.9.2. A full changelog is available at http://status.net/wiki/StatusNet_0.9.3.
Prerequisites Prerequisites
============= =============
@ -121,8 +108,8 @@ run correctly.
- PHP 5.2.3+. It may be possible to run this software on earlier - PHP 5.2.3+. It may be possible to run this software on earlier
versions of PHP, but many of the functions used are only available versions of PHP, but many of the functions used are only available
in PHP 5.2 or above. 5.2.6 or later is needed for XMPP background in PHP 5.2 or above. 5.2.6 or later is needed for XMPP background
daemons on 64-bit platforms. PHP 5.3.x should work but is known daemons on 64-bit platforms. PHP 5.3.x should work correctly in this
to cause some failures for OpenID. release, but problems with some plugins are possible.
- MySQL 5.x. The StatusNet database is stored, by default, in a MySQL - MySQL 5.x. The StatusNet database is stored, by default, in a MySQL
server. It has been primarily tested on 5.x servers, although it may server. It has been primarily tested on 5.x servers, although it may
be possible to install on earlier (or later!) versions. The server be possible to install on earlier (or later!) versions. The server

View File

@ -143,10 +143,10 @@ class AllAction extends ProfileAction
$message .= _('Try subscribing to more people, [join a group](%%action.groups%%) or post something yourself.'); $message .= _('Try subscribing to more people, [join a group](%%action.groups%%) or post something yourself.');
} else { } else {
// TRANS: %1$s is user nickname, %2$s is user nickname, %2$s is user nickname prefixed with "@" // TRANS: %1$s is user nickname, %2$s is user nickname, %2$s is user nickname prefixed with "@"
$message .= sprintf(_('You can try to [nudge %1$s](../%2$s) from his profile or [post something to his or her attention](%%%%action.newnotice%%%%?status_textarea=%3$s).'), $this->user->nickname, $this->user->nickname, '@' . $this->user->nickname); $message .= sprintf(_('You can try to [nudge %1$s](../%2$s) from their profile or [post something to them](%%%%action.newnotice%%%%?status_textarea=%3$s).'), $this->user->nickname, $this->user->nickname, '@' . $this->user->nickname);
} }
} else { } 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); $message .= sprintf(_('Why not [register an account](%%%%action.register%%%%) and then nudge %s or post a notice to them.'), $this->user->nickname);
} }
$this->elementStart('div', 'guide'); $this->elementStart('div', 'guide');

View File

@ -22,7 +22,7 @@
* @category API * @category API
* @package StatusNet * @package StatusNet
* @author Zach Copley <zach@status.net> * @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc. * @copyright 2009-2010 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
@ -131,7 +131,7 @@ class ApiAccountUpdateProfileColorsAction extends ApiAuthAction
try { try {
$this->setColors($design); $this->setColors($design);
} catch (WebColorException $e) { } catch (WebColorException $e) {
$this->clientError($e->getMessage()); $this->clientError($e->getMessage(), 400, $this->format);
return false; return false;
} }
@ -153,7 +153,7 @@ class ApiAccountUpdateProfileColorsAction extends ApiAuthAction
try { try {
$this->setColors($design); $this->setColors($design);
} catch (WebColorException $e) { } catch (WebColorException $e) {
$this->clientError($e->getMessage()); $this->clientError($e->getMessage(), 400, $this->format);
return false; return false;
} }

View File

@ -23,7 +23,7 @@
* @package StatusNet * @package StatusNet
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net> * @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc. * @copyright 2009-2010 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
@ -65,7 +65,7 @@ class ApiBlockCreateAction extends ApiAuthAction
parent::prepare($args); parent::prepare($args);
$this->user = $this->auth_user; $this->user = $this->auth_user;
$this->other = $this->getTargetUser($this->arg('id')); $this->other = $this->getTargetProfile($this->arg('id'));
return true; return true;
} }

View File

@ -23,7 +23,7 @@
* @package StatusNet * @package StatusNet
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net> * @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc. * @copyright 2009-2010 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
@ -64,7 +64,7 @@ class ApiBlockDestroyAction extends ApiAuthAction
parent::prepare($args); parent::prepare($args);
$this->user = $this->auth_user; $this->user = $this->auth_user;
$this->other = $this->getTargetUser($this->arg('id')); $this->other = $this->getTargetProfile($this->arg('id'));
return true; return true;
} }

View File

@ -24,7 +24,7 @@
* @author Dan Moore <dan@moore.cx> * @author Dan Moore <dan@moore.cx>
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net> * @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc. * @copyright 2009-2010 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
@ -67,7 +67,7 @@ class ApiFriendshipsCreateAction extends ApiAuthAction
parent::prepare($args); parent::prepare($args);
$this->user = $this->auth_user; $this->user = $this->auth_user;
$this->other = $this->getTargetUser($id); $this->other = $this->getTargetProfile($this->arg('id'));
return true; return true;
} }
@ -106,7 +106,7 @@ class ApiFriendshipsCreateAction extends ApiAuthAction
if (empty($this->other)) { if (empty($this->other)) {
$this->clientError( $this->clientError(
_('Could not follow user: User not found.'), _('Could not follow user: profile not found.'),
403, 403,
$this->format $this->format
); );

View File

@ -24,7 +24,7 @@
* @author Dan Moore <dan@moore.cx> * @author Dan Moore <dan@moore.cx>
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net> * @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc. * @copyright 2009-2010 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
@ -67,7 +67,7 @@ class ApiFriendshipsDestroyAction extends ApiAuthAction
parent::prepare($args); parent::prepare($args);
$this->user = $this->auth_user; $this->user = $this->auth_user;
$this->other = $this->getTargetUser($id); $this->other = $this->getTargetProfile($this->arg('id'));
return true; return true;
} }
@ -125,8 +125,7 @@ class ApiFriendshipsDestroyAction extends ApiAuthAction
} }
// throws an exception on error // throws an exception on error
Subscription::cancel($this->user->getProfile(), Subscription::cancel($this->user->getProfile(), $this->other);
$this->other->getProfile());
$this->initDocument($this->format); $this->initDocument($this->format);
$this->showProfile($this->other, $this->format); $this->showProfile($this->other, $this->format);

View File

@ -24,7 +24,7 @@
* @author Dan Moore <dan@moore.cx> * @author Dan Moore <dan@moore.cx>
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net> * @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc. * @copyright 2009-2010 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
@ -50,8 +50,8 @@ require_once INSTALLDIR . '/lib/apiprivateauth.php';
class ApiFriendshipsExistsAction extends ApiPrivateAuthAction class ApiFriendshipsExistsAction extends ApiPrivateAuthAction
{ {
var $user_a = null; var $profile_a = null;
var $user_b = null; var $profile_b = null;
/** /**
* Take arguments for running * Take arguments for running
@ -66,11 +66,8 @@ class ApiFriendshipsExistsAction extends ApiPrivateAuthAction
{ {
parent::prepare($args); parent::prepare($args);
$user_a_id = $this->trimmed('user_a'); $this->profile_a = $this->getTargetProfile($this->trimmed('user_a'));
$user_b_id = $this->trimmed('user_b'); $this->profile_b = $this->getTargetProfile($this->trimmed('user_b'));
$this->user_a = $this->getTargetUser($user_a_id);
$this->user_b = $this->getTargetUser($user_b_id);
return true; return true;
} }
@ -89,16 +86,16 @@ class ApiFriendshipsExistsAction extends ApiPrivateAuthAction
{ {
parent::handle($args); parent::handle($args);
if (empty($this->user_a) || empty($this->user_b)) { if (empty($this->profile_a) || empty($this->profile_b)) {
$this->clientError( $this->clientError(
_('Two user ids or screen_names must be supplied.'), _('Two valid IDs or screen_names must be supplied.'),
400, 400,
$this->format $this->format
); );
return; return;
} }
$result = $this->user_a->isSubscribed($this->user_b); $result = Subscription::exists($this->profile_a, $this->profile_b);
switch ($this->format) { switch ($this->format) {
case 'xml': case 'xml':

View File

@ -88,15 +88,15 @@ class ApiMediaUploadAction extends ApiAuthAction
try { try {
$upload = MediaFile::fromUpload('media', $this->auth_user); $upload = MediaFile::fromUpload('media', $this->auth_user);
} catch (ClientException $ce) { } catch (Exception $e) {
$this->clientError($ce->getMessage()); $this->clientError($e->getMessage(), $e->getCode());
return; return;
} }
if (isset($upload)) { if (isset($upload)) {
$this->showResponse($upload); $this->showResponse($upload);
} else { } else {
$this->clientError('Upload failed.'); $this->clientError(_('Upload failed.'));
return; return;
} }
} }

View File

@ -196,7 +196,8 @@ class ApiStatusesUpdateAction extends ApiAuthAction
if ($_SERVER['REQUEST_METHOD'] != 'POST') { if ($_SERVER['REQUEST_METHOD'] != 'POST') {
$this->clientError( $this->clientError(
_('This method requires a POST.'), _('This method requires a POST.'),
400, $this->format 400,
$this->format
); );
return; return;
} }
@ -217,7 +218,7 @@ class ApiStatusesUpdateAction extends ApiAuthAction
if (empty($this->status)) { if (empty($this->status)) {
$this->clientError( $this->clientError(
'Client must provide a \'status\' parameter with a value.', _('Client must provide a \'status\' parameter with a value.'),
400, 400,
$this->format $this->format
); );
@ -291,8 +292,8 @@ class ApiStatusesUpdateAction extends ApiAuthAction
try { try {
$upload = MediaFile::fromUpload('media', $this->auth_user); $upload = MediaFile::fromUpload('media', $this->auth_user);
} catch (ClientException $ce) { } catch (Exception $e) {
$this->clientError($ce->getMessage()); $this->clientError($e->getMessage(), $e->getCode(), $this->format);
return; return;
} }
@ -305,7 +306,11 @@ class ApiStatusesUpdateAction extends ApiAuthAction
'Max notice size is %d chars, ' . 'Max notice size is %d chars, ' .
'including attachment URL.' 'including attachment URL.'
); );
$this->clientError(sprintf($msg, Notice::maxContent())); $this->clientError(
sprintf($msg, Notice::maxContent()),
400,
$this->format
);
} }
} }
@ -332,7 +337,7 @@ class ApiStatusesUpdateAction extends ApiAuthAction
$options $options
); );
} catch (Exception $e) { } catch (Exception $e) {
$this->clientError($e->getMessage()); $this->clientError($e->getMessage(), $e->getCode(), $this->format);
return; return;
} }

View File

@ -25,7 +25,7 @@
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @author Jeffery To <jeffery.to@gmail.com> * @author Jeffery To <jeffery.to@gmail.com>
* @author Zach Copley <zach@status.net> * @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc. * @copyright 2009-2010 StatusNet, Inc.
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
@ -138,7 +138,9 @@ class ApiTimelineGroupAction extends ApiPrivateAuthAction
$this->raw($atom->getString()); $this->raw($atom->getString());
} catch (Atom10FeedException $e) { } catch (Atom10FeedException $e) {
$this->serverError( $this->serverError(
'Could not generate feed for group - ' . $e->getMessage() 'Could not generate feed for group - ' . $e->getMessage(),
400,
$this->format
); );
return; return;
} }

View File

@ -104,7 +104,7 @@ class FavorAction extends Action
} }
/** /**
* Notifies a user when his notice is favorited. * Notifies a user when their notice is favorited.
* *
* @param class $notice favorited notice * @param class $notice favorited notice
* @param class $user user declaring a favorite * @param class $user user declaring a favorite

View File

@ -37,7 +37,7 @@ require_once INSTALLDIR.'/lib/omb.php';
* Handler for remote subscription finish callback * Handler for remote subscription finish callback
* *
* When a remote user subscribes a local user, a redirect to this action is * When a remote user subscribes a local user, a redirect to this action is
* issued after the remote user authorized his service to subscribe. * issued after the remote user authorized their service to subscribe.
* *
* @category Action * @category Action
* @package Laconica * @package Laconica

View File

@ -82,7 +82,7 @@ class NudgeAction extends Action
} }
if (!$other->email || !$other->emailnotifynudge) { if (!$other->email || !$other->emailnotifynudge) {
$this->clientError(_('This user doesn\'t allow nudges or hasn\'t confirmed or set his email yet.')); $this->clientError(_('This user doesn\'t allow nudges or hasn\'t confirmed or set their email yet.'));
return; return;
} }

View File

@ -196,18 +196,18 @@ class RepliesAction extends OwnerDesignAction
function showEmptyListMessage() function showEmptyListMessage()
{ {
$message = sprintf(_('This is the timeline showing replies to %1$s but %2$s hasn\'t received a notice to his attention yet.'), $this->user->nickname, $this->user->nickname) . ' '; $message = sprintf(_('This is the timeline showing replies to %1$s but %2$s hasn\'t received a notice to them yet.'), $this->user->nickname, $this->user->nickname) . ' ';
if (common_logged_in()) { if (common_logged_in()) {
$current_user = common_current_user(); $current_user = common_current_user();
if ($this->user->id === $current_user->id) { if ($this->user->id === $current_user->id) {
$message .= _('You can engage other users in a conversation, subscribe to more people or [join groups](%%action.groups%%).'); $message .= _('You can engage other users in a conversation, subscribe to more people or [join groups](%%action.groups%%).');
} else { } else {
$message .= sprintf(_('You can try to [nudge %1$s](../%2$s) or [post something to his or her attention](%%%%action.newnotice%%%%?status_textarea=%3$s).'), $this->user->nickname, $this->user->nickname, '@' . $this->user->nickname); $message .= sprintf(_('You can try to [nudge %1$s](../%2$s) or [post something to them](%%%%action.newnotice%%%%?status_textarea=%3$s).'), $this->user->nickname, $this->user->nickname, '@' . $this->user->nickname);
} }
} }
else { 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); $message .= sprintf(_('Why not [register an account](%%%%action.register%%%%) and then nudge %s or post a notice to them.'), $this->user->nickname);
} }
$this->elementStart('div', 'guide'); $this->elementStart('div', 'guide');

View File

@ -119,7 +119,7 @@ class ShowfavoritesAction extends OwnerDesignAction
if (!empty($cur) && $cur->id == $this->user->id) { if (!empty($cur) && $cur->id == $this->user->id) {
// Show imported/gateway notices as well as local if // Show imported/gateway notices as well as local if
// the user is looking at his own favorites // the user is looking at their own favorites
$this->notice = $this->user->favoriteNotices(true, ($this->page-1)*NOTICES_PER_PAGE, $this->notice = $this->user->favoriteNotices(true, ($this->page-1)*NOTICES_PER_PAGE,
NOTICES_PER_PAGE + 1); NOTICES_PER_PAGE + 1);
@ -205,11 +205,11 @@ class ShowfavoritesAction extends OwnerDesignAction
if ($this->user->id === $current_user->id) { if ($this->user->id === $current_user->id) {
$message = _('You haven\'t chosen any favorite notices yet. Click the fave button on notices you like to bookmark them for later or shed a spotlight on them.'); $message = _('You haven\'t chosen any favorite notices yet. Click the fave button on notices you like to bookmark them for later or shed a spotlight on them.');
} else { } else {
$message = sprintf(_('%s hasn\'t added any notices to his favorites yet. Post something interesting they would add to their favorites :)'), $this->user->nickname); $message = sprintf(_('%s hasn\'t added any favorite notices yet. Post something interesting they would add to their favorites :)'), $this->user->nickname);
} }
} }
else { else {
$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); $message = sprintf(_('%s hasn\'t added any favorite notices 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'); $this->elementStart('div', 'guide');

View File

@ -198,11 +198,11 @@ class ShowstreamAction extends ProfileAction
if ($this->user->id === $current_user->id) { if ($this->user->id === $current_user->id) {
$message .= _('Seen anything interesting recently? You haven\'t posted any notices yet, now would be a good time to start :)'); $message .= _('Seen anything interesting recently? You haven\'t posted any notices yet, now would be a good time to start :)');
} else { } else {
$message .= sprintf(_('You can try to nudge %1$s or [post something to his or her attention](%%%%action.newnotice%%%%?status_textarea=%2$s).'), $this->user->nickname, '@' . $this->user->nickname); $message .= sprintf(_('You can try to nudge %1$s or [post something to them](%%%%action.newnotice%%%%?status_textarea=%2$s).'), $this->user->nickname, '@' . $this->user->nickname);
} }
} }
else { 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); $message .= sprintf(_('Why not [register an account](%%%%action.register%%%%) and then nudge %s or post a notice to them.'), $this->user->nickname);
} }
$this->elementStart('div', 'guide'); $this->elementStart('div', 'guide');

View File

@ -139,7 +139,8 @@ class File extends Memcached_DataObject
$redir_url = $redir_data; $redir_url = $redir_data;
$redir_data = array(); $redir_data = array();
} else { } else {
throw new ServerException("Can't process url '$given_url'"); // TRANS: Server exception thrown when a URL cannot be processed.
throw new ServerException(sprintf(_("Cannot process URL '%s'"), $given_url));
} }
// TODO: max field length // TODO: max field length
if ($redir_url === $given_url || strlen($redir_url) > 255 || !$followRedirects) { if ($redir_url === $given_url || strlen($redir_url) > 255 || !$followRedirects) {
@ -169,7 +170,9 @@ class File extends Memcached_DataObject
if (empty($x)) { if (empty($x)) {
$x = File::staticGet($file_id); $x = File::staticGet($file_id);
if (empty($x)) { if (empty($x)) {
throw new ServerException("Robin thinks something is impossible."); // FIXME: This could possibly be a clearer message :)
// TRANS: Server exception thrown when... Robin thinks something is impossible!
throw new ServerException(_("Robin thinks something is impossible."));
} }
} }
@ -182,8 +185,10 @@ class File extends Memcached_DataObject
function isRespectsQuota($user,$fileSize) { function isRespectsQuota($user,$fileSize) {
if ($fileSize > common_config('attachments', 'file_quota')) { if ($fileSize > common_config('attachments', 'file_quota')) {
return sprintf(_('No file may be larger than %d bytes ' . // TRANS: Message given if an upload is larger than the configured maximum.
'and the file you sent was %d bytes. Try to upload a smaller version.'), // TRANS: %1$d is the byte limit for uploads, %2$d is the byte count for the uploaded file.
return sprintf(_('No file may be larger than %1$d bytes ' .
'and the file you sent was %2$d bytes. Try to upload a smaller version.'),
common_config('attachments', 'file_quota'), $fileSize); common_config('attachments', 'file_quota'), $fileSize);
} }
@ -192,6 +197,8 @@ class File extends Memcached_DataObject
$this->fetch(); $this->fetch();
$total = $this->total + $fileSize; $total = $this->total + $fileSize;
if ($total > common_config('attachments', 'user_quota')) { if ($total > common_config('attachments', 'user_quota')) {
// TRANS: Message given if an upload would exceed user quota.
// TRANS: %d (number) is the user quota in bytes.
return sprintf(_('A file this large would exceed your user quota of %d bytes.'), common_config('attachments', 'user_quota')); return sprintf(_('A file this large would exceed your user quota of %d bytes.'), common_config('attachments', 'user_quota'));
} }
$query .= ' AND EXTRACT(month FROM file.modified) = EXTRACT(month FROM now()) and EXTRACT(year FROM file.modified) = EXTRACT(year FROM now())'; $query .= ' AND EXTRACT(month FROM file.modified) = EXTRACT(month FROM now()) and EXTRACT(year FROM file.modified) = EXTRACT(year FROM now())';
@ -199,6 +206,8 @@ class File extends Memcached_DataObject
$this->fetch(); $this->fetch();
$total = $this->total + $fileSize; $total = $this->total + $fileSize;
if ($total > common_config('attachments', 'monthly_quota')) { if ($total > common_config('attachments', 'monthly_quota')) {
// TRANS: Message given id an upload would exceed a user's monthly quota.
// TRANS: $d (number) is the monthly user quota in bytes.
return sprintf(_('A file this large would exceed your monthly quota of %d bytes.'), common_config('attachments', 'monthly_quota')); return sprintf(_('A file this large would exceed your monthly quota of %d bytes.'), common_config('attachments', 'monthly_quota'));
} }
return true; return true;
@ -235,7 +244,8 @@ class File extends Memcached_DataObject
static function path($filename) static function path($filename)
{ {
if (!self::validFilename($filename)) { if (!self::validFilename($filename)) {
throw new ClientException("Invalid filename"); // TRANS: Client exception thrown if a file upload does not have a valid name.
throw new ClientException(_("Invalid filename."));
} }
$dir = common_config('attachments', 'dir'); $dir = common_config('attachments', 'dir');
@ -249,7 +259,8 @@ class File extends Memcached_DataObject
static function url($filename) static function url($filename)
{ {
if (!self::validFilename($filename)) { if (!self::validFilename($filename)) {
throw new ClientException("Invalid filename"); // TRANS: Client exception thrown if a file upload does not have a valid name.
throw new ClientException(_("Invalid filename."));
} }
if(common_config('site','private')) { if(common_config('site','private')) {
@ -302,6 +313,7 @@ class File extends Memcached_DataObject
if(! isset($this->filename)){ if(! isset($this->filename)){
$notEnclosureMimeTypes = array(null,'text/html','application/xhtml+xml'); $notEnclosureMimeTypes = array(null,'text/html','application/xhtml+xml');
$mimetype = $this->mimetype;
if($mimetype != null){ if($mimetype != null){
$mimetype = strtolower($this->mimetype); $mimetype = strtolower($this->mimetype);
} }
@ -341,4 +353,3 @@ class File extends Memcached_DataObject
return !empty($enclosure); return !empty($enclosure);
} }
} }

View File

@ -39,6 +39,22 @@ class Foreign_user extends Memcached_DataObject
return null; return null;
} }
static function getByNickname($nickname, $service)
{
if (empty($nickname) || empty($service)) {
return null;
} else {
$fuser = new Foreign_user();
$fuser->service = $service;
$fuser->nickname = $nickname;
$fuser->limit(1);
$result = $fuser->find(true);
return empty($result) ? null : $fuser;
}
}
function updateKeys(&$orig) function updateKeys(&$orig)
{ {
$this->_connect(); $this->_connect();

View File

@ -38,6 +38,7 @@ class Group_member extends Memcached_DataObject
if (!$result) { if (!$result) {
common_log_db_error($member, 'INSERT', __FILE__); common_log_db_error($member, 'INSERT', __FILE__);
// TRANS: Exception thrown when joining a group fails.
throw new Exception(_("Group join failed.")); throw new Exception(_("Group join failed."));
} }
@ -50,6 +51,7 @@ class Group_member extends Memcached_DataObject
'profile_id' => $profile_id)); 'profile_id' => $profile_id));
if (empty($member)) { if (empty($member)) {
// TRANS: Exception thrown when trying to leave a group the user is not a member of.
throw new Exception(_("Not part of group.")); throw new Exception(_("Not part of group."));
} }
@ -57,6 +59,7 @@ class Group_member extends Memcached_DataObject
if (!$result) { if (!$result) {
common_log_db_error($member, 'INSERT', __FILE__); common_log_db_error($member, 'INSERT', __FILE__);
// TRANS: Exception thrown when trying to leave a group fails.
throw new Exception(_("Group leave failed.")); throw new Exception(_("Group leave failed."));
} }

View File

@ -38,6 +38,7 @@ class Local_group extends Memcached_DataObject
$this->encache(); $this->encache();
} else { } else {
common_log_db_error($local, 'UPDATE', __FILE__); common_log_db_error($local, 'UPDATE', __FILE__);
// TRANS: Server exception thrown when updating a local group fails.
throw new ServerException(_('Could not update local group.')); throw new ServerException(_('Could not update local group.'));
} }

View File

@ -73,6 +73,8 @@ class Login_token extends Memcached_DataObject
if (!$result) { if (!$result) {
common_log_db_error($login_token, 'INSERT', __FILE__); common_log_db_error($login_token, 'INSERT', __FILE__);
// TRANS: Exception thrown when trying creating a login token failed.
// TRANS: %s is the user nickname for which token creation failed.
throw new Exception(sprintf(_('Could not create login token for %s'), throw new Exception(sprintf(_('Could not create login token for %s'),
$user->nickname)); $user->nickname));
} }

View File

@ -235,6 +235,7 @@ class Memcached_DataObject extends Safe_DataObject
$pkey[] = $key; $pkey[] = $key;
$pval[] = self::valueString($this->$key); $pval[] = self::valueString($this->$key);
} else { } else {
// Low level exception. No need for i18n as discussed with Brion.
throw new Exception("Unknown key type $key => $type for " . $this->tableName()); throw new Exception("Unknown key type $key => $type for " . $this->tableName());
} }
} }
@ -282,6 +283,7 @@ class Memcached_DataObject extends Safe_DataObject
} else if ($type == 'fulltext') { } else if ($type == 'fulltext') {
$search_engine = new MySQLSearch($this, $table); $search_engine = new MySQLSearch($this, $table);
} else { } else {
// Low level exception. No need for i18n as discussed with Brion.
throw new ServerException('Unknown search type: ' . $type); throw new ServerException('Unknown search type: ' . $type);
} }
} else { } else {
@ -527,7 +529,8 @@ class Memcached_DataObject extends Safe_DataObject
} }
if (!$dsn) { if (!$dsn) {
throw new Exception("No database name / dsn found anywhere"); // TRANS: Exception thrown when database name or Data Source Name could not be found.
throw new Exception(_("No database name or DSN found anywhere."));
} }
return $dsn; return $dsn;
@ -577,6 +580,7 @@ class Memcached_DataObject extends Safe_DataObject
if ($message instanceof PEAR_Error) { if ($message instanceof PEAR_Error) {
$message = $message->getMessage(); $message = $message->getMessage();
} }
// Low level exception. No need for i18n as discussed with Brion.
throw new ServerException("[$id] DB_DataObject error [$type]: $message"); throw new ServerException("[$id] DB_DataObject error [$type]: $message");
} }
@ -593,7 +597,7 @@ class Memcached_DataObject extends Safe_DataObject
return $c->get($cacheKey); return $c->get($cacheKey);
} }
static function cacheSet($keyPart, $value) static function cacheSet($keyPart, $value, $flag=null, $expiry=null)
{ {
$c = self::memcache(); $c = self::memcache();
@ -603,7 +607,7 @@ class Memcached_DataObject extends Safe_DataObject
$cacheKey = common_cache_key($keyPart); $cacheKey = common_cache_key($keyPart);
return $c->set($cacheKey, $value); return $c->set($cacheKey, $value, $flag, $expiry);
} }
static function valueString($v) static function valueString($v)
@ -619,9 +623,11 @@ class Memcached_DataObject extends Safe_DataObject
case 'sql': case 'sql':
case 'datetime': case 'datetime':
case 'time': case 'time':
// Low level exception. No need for i18n as discussed with Brion.
throw new ServerException("Unhandled DB_DataObject_Cast type passed as cacheKey value: '$v->type'"); throw new ServerException("Unhandled DB_DataObject_Cast type passed as cacheKey value: '$v->type'");
break; break;
default: default:
// Low level exception. No need for i18n as discussed with Brion.
throw new ServerException("Unknown DB_DataObject_Cast type passed as cacheKey value: '$v->type'"); throw new ServerException("Unknown DB_DataObject_Cast type passed as cacheKey value: '$v->type'");
break; break;
} }

View File

@ -42,6 +42,7 @@ class Message extends Memcached_DataObject
$sender = Profile::staticGet('id', $from); $sender = Profile::staticGet('id', $from);
if (!$sender->hasRight(Right::NEWMESSAGE)) { if (!$sender->hasRight(Right::NEWMESSAGE)) {
// TRANS: Client exception thrown when a user tries to send a direct message while being banned from sending them.
throw new ClientException(_('You are banned from sending direct messages.')); throw new ClientException(_('You are banned from sending direct messages.'));
} }
@ -58,6 +59,7 @@ class Message extends Memcached_DataObject
if (!$result) { if (!$result) {
common_log_db_error($msg, 'INSERT', __FILE__); common_log_db_error($msg, 'INSERT', __FILE__);
// TRANS: Message given when a message could not be stored on the server.
return _('Could not insert message.'); return _('Could not insert message.');
} }
@ -68,6 +70,7 @@ class Message extends Memcached_DataObject
if (!$result) { if (!$result) {
common_log_db_error($msg, 'UPDATE', __FILE__); common_log_db_error($msg, 'UPDATE', __FILE__);
// TRANS: Message given when a message could not be updated on the server.
return _('Could not update message with new URI.'); return _('Could not update message with new URI.');
} }

View File

@ -42,10 +42,10 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
*/ */
require_once INSTALLDIR.'/classes/Memcached_DataObject.php'; require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
/* We keep the first three 20-notice pages, plus one for pagination check, /* We keep 200 notices, the max number of notices available per API request,
* in the memcached cache. */ * in the memcached cache. */
define('NOTICE_CACHE_WINDOW', 61); define('NOTICE_CACHE_WINDOW', 200);
define('MAX_BOXCARS', 128); define('MAX_BOXCARS', 128);
@ -90,7 +90,15 @@ class Notice extends Memcached_DataObject
function getProfile() function getProfile()
{ {
return Profile::staticGet('id', $this->profile_id); $profile = Profile::staticGet('id', $this->profile_id);
if (empty($profile)) {
// TRANS: Server exception thrown when a user profile for a notice cannot be found.
// TRANS: %1$d is a profile ID (number), %2$d is a notice ID (number).
throw new ServerException(sprintf(_('No such profile (%1$d) for notice (%2$d).'), $this->profile_id, $this->id));
}
return $profile;
} }
function delete() function delete()
@ -248,28 +256,34 @@ class Notice extends Memcached_DataObject
$final = common_shorten_links($content); $final = common_shorten_links($content);
if (Notice::contentTooLong($final)) { if (Notice::contentTooLong($final)) {
// TRANS: Client exception thrown if a notice contains too many characters.
throw new ClientException(_('Problem saving notice. Too long.')); throw new ClientException(_('Problem saving notice. Too long.'));
} }
if (empty($profile)) { if (empty($profile)) {
// TRANS: Client exception thrown when trying to save a notice for an unknown user.
throw new ClientException(_('Problem saving notice. Unknown user.')); throw new ClientException(_('Problem saving notice. Unknown user.'));
} }
if (common_config('throttle', 'enabled') && !Notice::checkEditThrottle($profile_id)) { if (common_config('throttle', 'enabled') && !Notice::checkEditThrottle($profile_id)) {
common_log(LOG_WARNING, 'Excessive posting by profile #' . $profile_id . '; throttled.'); common_log(LOG_WARNING, 'Excessive posting by profile #' . $profile_id . '; throttled.');
// TRANS: Client exception thrown when a user tries to post too many notices in a given time frame.
throw new ClientException(_('Too many notices too fast; take a breather '. throw new ClientException(_('Too many notices too fast; take a breather '.
'and post again in a few minutes.')); 'and post again in a few minutes.'));
} }
if (common_config('site', 'dupelimit') > 0 && !Notice::checkDupes($profile_id, $final)) { if (common_config('site', 'dupelimit') > 0 && !Notice::checkDupes($profile_id, $final)) {
common_log(LOG_WARNING, 'Dupe posting by profile #' . $profile_id . '; throttled.'); common_log(LOG_WARNING, 'Dupe posting by profile #' . $profile_id . '; throttled.');
// TRANS: Client exception thrown when a user tries to post too many duplicate notices in a given time frame.
throw new ClientException(_('Too many duplicate messages too quickly;'. throw new ClientException(_('Too many duplicate messages too quickly;'.
' take a breather and post again in a few minutes.')); ' take a breather and post again in a few minutes.'));
} }
if (!$profile->hasRight(Right::NEWNOTICE)) { if (!$profile->hasRight(Right::NEWNOTICE)) {
common_log(LOG_WARNING, "Attempted post from user disallowed to post: " . $profile->nickname); common_log(LOG_WARNING, "Attempted post from user disallowed to post: " . $profile->nickname);
throw new ClientException(_('You are banned from posting notices on this site.'));
// TRANS: Client exception thrown when a user tries to post while being banned.
throw new ClientException(_('You are banned from posting notices on this site.'), 403);
} }
$notice = new Notice(); $notice = new Notice();
@ -335,6 +349,7 @@ class Notice extends Memcached_DataObject
if (!$id) { if (!$id) {
common_log_db_error($notice, 'INSERT', __FILE__); common_log_db_error($notice, 'INSERT', __FILE__);
// TRANS: Server exception thrown when a notice cannot be saved.
throw new ServerException(_('Problem saving notice.')); throw new ServerException(_('Problem saving notice.'));
} }
@ -361,6 +376,7 @@ class Notice extends Memcached_DataObject
if ($changed) { if ($changed) {
if (!$notice->update($orig)) { if (!$notice->update($orig)) {
common_log_db_error($notice, 'UPDATE', __FILE__); common_log_db_error($notice, 'UPDATE', __FILE__);
// TRANS: Server exception thrown when a notice cannot be updated.
throw new ServerException(_('Problem saving notice.')); throw new ServerException(_('Problem saving notice.'));
} }
} }
@ -872,7 +888,8 @@ class Notice extends Memcached_DataObject
function saveKnownGroups($group_ids) function saveKnownGroups($group_ids)
{ {
if (!is_array($group_ids)) { if (!is_array($group_ids)) {
throw new ServerException("Bad type provided to saveKnownGroups"); // TRANS: Server exception thrown when no array is provided to the method saveKnownGroups().
throw new ServerException(_("Bad type provided to saveKnownGroups"));
} }
$groups = array(); $groups = array();
@ -970,6 +987,7 @@ class Notice extends Memcached_DataObject
if (!$result) { if (!$result) {
common_log_db_error($gi, 'INSERT', __FILE__); common_log_db_error($gi, 'INSERT', __FILE__);
// TRANS: Server exception thrown when an update for a group inbox fails.
throw new ServerException(_('Problem saving group inbox.')); throw new ServerException(_('Problem saving group inbox.'));
} }
@ -1075,7 +1093,9 @@ class Notice extends Memcached_DataObject
if (!$id) { if (!$id) {
common_log_db_error($reply, 'INSERT', __FILE__); common_log_db_error($reply, 'INSERT', __FILE__);
throw new ServerException("Couldn't save reply for {$this->id}, {$mentioned->id}"); // TRANS: Server exception thrown when a reply cannot be saved.
// TRANS: %1$d is a notice ID, %2$d is the ID of the mentioned user.
throw new ServerException(sprintf(_("Could not save reply for %1$d, %2$d."), $this->id, $mentioned->id));
} else { } else {
$replied[$mentioned->id] = 1; $replied[$mentioned->id] = 1;
self::blow('reply:stream:%d', $mentioned->id); self::blow('reply:stream:%d', $mentioned->id);
@ -1178,6 +1198,9 @@ class Notice extends Memcached_DataObject
return $groups; return $groups;
} }
// This has gotten way too long. Needs to be sliced up into functional bits
// or ideally exported to a utility class.
function asAtomEntry($namespace=false, $source=false, $author=true, $cur=null) function asAtomEntry($namespace=false, $source=false, $author=true, $cur=null)
{ {
$profile = $this->getProfile(); $profile = $this->getProfile();
@ -1197,74 +1220,176 @@ class Notice extends Memcached_DataObject
$attrs = array(); $attrs = array();
} }
$xs->elementStart('entry', $attrs); if (Event::handle('StartActivityStart', array(&$this, &$xs, &$attrs))) {
$xs->elementStart('entry', $attrs);
Event::handle('EndActivityStart', array(&$this, &$xs, &$attrs));
}
if ($source) { if (Event::handle('StartActivitySource', array(&$this, &$xs))) {
$xs->elementStart('source');
$xs->element('id', null, $profile->profileurl); if ($source) {
$xs->element('title', null, $profile->nickname . " - " . common_config('site', 'name'));
$xs->element('link', array('href' => $profile->profileurl)); $atom_feed = $profile->getAtomFeed();
$user = User::staticGet('id', $profile->id);
if (!empty($user)) { if (!empty($atom_feed)) {
$atom_feed = common_local_url('ApiTimelineUser',
array('format' => 'atom', $xs->elementStart('source');
'id' => $profile->nickname));
$xs->element('link', array('rel' => 'self', // XXX: we should store the actual feed ID
'type' => 'application/atom+xml',
'href' => $profile->profileurl)); $xs->element('id', null, $atom_feed);
$xs->element('link', array('rel' => 'license',
'href' => common_config('license', 'url'))); // XXX: we should store the actual feed title
$xs->element('title', null, $profile->getBestName());
$xs->element('link', array('rel' => 'alternate',
'type' => 'text/html',
'href' => $profile->profileurl));
$xs->element('link', array('rel' => 'self',
'type' => 'application/atom+xml',
'href' => $atom_feed));
$xs->element('icon', null, $profile->avatarUrl(AVATAR_PROFILE_SIZE));
$notice = $profile->getCurrentNotice();
if (!empty($notice)) {
$xs->element('updated', null, self::utcDate($notice->created));
}
$user = User::staticGet('id', $profile->id);
if (!empty($user)) {
$xs->element('link', array('rel' => 'license',
'href' => common_config('license', 'url')));
}
$xs->elementEnd('source');
}
} }
Event::handle('EndActivitySource', array(&$this, &$xs));
$xs->element('icon', null, $profile->avatarUrl(AVATAR_PROFILE_SIZE));
$xs->element('updated', null, common_date_w3dtf($this->created));
} }
if ($source) { $title = common_xml_safe_str($this->content);
$xs->elementEnd('source');
if (Event::handle('StartActivityTitle', array(&$this, &$xs, &$title))) {
$xs->element('title', null, $title);
Event::handle('EndActivityTitle', array($this, &$xs, $title));
} }
$xs->element('title', null, common_xml_safe_str($this->content)); $atomAuthor = '';
if ($author) { if ($author) {
$xs->raw($profile->asAtomAuthor($cur)); $atomAuthor = $profile->asAtomAuthor($cur);
$xs->raw($profile->asActivityActor());
} }
$xs->element('link', array('rel' => 'alternate', if (Event::handle('StartActivityAuthor', array(&$this, &$xs, &$atomAuthor))) {
'type' => 'text/html', if (!empty($atomAuthor)) {
'href' => $this->bestUrl())); $xs->raw($atomAuthor);
Event::handle('EndActivityAuthor', array(&$this, &$xs, &$atomAuthor));
$xs->element('id', null, $this->uri);
$xs->element('published', null, common_date_w3dtf($this->created));
$xs->element('updated', null, common_date_w3dtf($this->created));
$source = null;
$ns = $this->getSource();
if ($ns) {
if (!empty($ns->name) && !empty($ns->url)) {
$source = '<a href="'
. htmlspecialchars($ns->url)
. '" rel="nofollow">'
. htmlspecialchars($ns->name)
. '</a>';
} else {
$source = $ns->code;
} }
} }
$noticeInfoAttr = array( $actor = '';
'local_id' => $this->id, // local notice ID (useful to clients for ordering)
'source' => $source, // the client name (source attribution) if ($author) {
); $actor = $profile->asActivityActor();
}
if (Event::handle('StartActivityActor', array(&$this, &$xs, &$actor))) {
if (!empty($actor)) {
$xs->raw($actor);
Event::handle('EndActivityActor', array(&$this, &$xs, &$actor));
}
}
$url = $this->bestUrl();
if (Event::handle('StartActivityLink', array(&$this, &$xs, &$url))) {
$xs->element('link', array('rel' => 'alternate',
'type' => 'text/html',
'href' => $url));
Event::handle('EndActivityLink', array(&$this, &$xs, $url));
}
$id = $this->uri;
if (Event::handle('StartActivityId', array(&$this, &$xs, &$id))) {
$xs->element('id', null, $id);
Event::handle('EndActivityId', array(&$this, &$xs, $id));
}
$published = self::utcDate($this->created);
if (Event::handle('StartActivityPublished', array(&$this, &$xs, &$published))) {
$xs->element('published', null, $published);
Event::handle('EndActivityPublished', array(&$this, &$xs, $published));
}
$updated = $published; // XXX: notices are usually immutable
if (Event::handle('StartActivityUpdated', array(&$this, &$xs, &$updated))) {
$xs->element('updated', null, $updated);
Event::handle('EndActivityUpdated', array(&$this, &$xs, $updated));
}
$content = common_xml_safe_str($this->rendered);
if (Event::handle('StartActivityContent', array(&$this, &$xs, &$content))) {
$xs->element('content', array('type' => 'html'), $content);
Event::handle('EndActivityContent', array(&$this, &$xs, $content));
}
// Most of our notices represent POSTing a NOTE. This is the default verb
// for activity streams, so we normally just leave it out.
$verb = ActivityVerb::POST;
if (Event::handle('StartActivityVerb', array(&$this, &$xs, &$verb))) {
$xs->element('activity:verb', null, $verb);
Event::handle('EndActivityVerb', array(&$this, &$xs, $verb));
}
// We use the default behavior for activity streams: if there's no activity:object,
// then treat the entry itself as the object. Here, you can set the type of that object,
// which is normally a NOTE.
$type = ActivityObject::NOTE;
if (Event::handle('StartActivityDefaultObjectType', array(&$this, &$xs, &$type))) {
$xs->element('activity:object-type', null, $type);
Event::handle('EndActivityDefaultObjectType', array(&$this, &$xs, $type));
}
// Since we usually use the entry itself as an object, we don't have an explicit
// object. Some extensions may want to add them (for photo, event, music, etc.).
$objects = array();
if (Event::handle('StartActivityObjects', array(&$this, &$xs, &$objects))) {
foreach ($objects as $object) {
$xs->raw($object->asString());
}
Event::handle('EndActivityObjects', array(&$this, &$xs, $objects));
}
$noticeInfoAttr = array('local_id' => $this->id); // local notice ID (useful to clients for ordering)
$ns = $this->getSource(); $ns = $this->getSource();
if ($ns) {
if (!empty($ns)) {
$noticeInfoAttr['source'] = $ns->code;
if (!empty($ns->url)) { if (!empty($ns->url)) {
$noticeInfoAttr['source_link'] = $ns->url; $noticeInfoAttr['source_link'] = $ns->url;
if (!empty($ns->name)) {
$noticeInfoAttr['source'] = '<a href="'
. htmlspecialchars($ns->url)
. '" rel="nofollow">'
. htmlspecialchars($ns->name)
. '</a>';
}
} }
} }
@ -1278,103 +1403,143 @@ class Notice extends Memcached_DataObject
$noticeInfoAttr['repeat_of'] = $this->repeat_of; $noticeInfoAttr['repeat_of'] = $this->repeat_of;
} }
$xs->element('statusnet:notice_info', $noticeInfoAttr, null); if (Event::handle('StartActivityNoticeInfo', array(&$this, &$xs, &$noticeInfoAttr))) {
$xs->element('statusnet:notice_info', $noticeInfoAttr, null);
Event::handle('EndActivityNoticeInfo', array(&$this, &$xs, $noticeInfoAttr));
}
$replyNotice = null;
if ($this->reply_to) { if ($this->reply_to) {
$reply_notice = Notice::staticGet('id', $this->reply_to); $replyNotice = Notice::staticGet('id', $this->reply_to);
if (!empty($reply_notice)) { }
if (Event::handle('StartActivityInReplyTo', array(&$this, &$xs, &$replyNotice))) {
if (!empty($replyNotice)) {
$xs->element('link', array('rel' => 'related', $xs->element('link', array('rel' => 'related',
'href' => $reply_notice->bestUrl())); 'href' => $replyNotice->bestUrl()));
$xs->element('thr:in-reply-to', $xs->element('thr:in-reply-to',
array('ref' => $reply_notice->uri, array('ref' => $replyNotice->uri,
'href' => $reply_notice->bestUrl())); 'href' => $replyNotice->bestUrl()));
Event::handle('EndActivityInReplyTo', array(&$this, &$xs, $replyNotice));
} }
} }
$conv = null;
if (!empty($this->conversation)) { if (!empty($this->conversation)) {
$conv = Conversation::staticGet('id', $this->conversation); $conv = Conversation::staticGet('id', $this->conversation);
if (!empty($conv)) {
$xs->element(
'link', array(
'rel' => 'ostatus:conversation',
'href' => $conv->uri
)
);
}
} }
if (Event::handle('StartActivityConversation', array(&$this, &$xs, &$conv))) {
if (!empty($conv)) {
$xs->element('link', array('rel' => 'ostatus:conversation',
'href' => $conv->uri));
}
Event::handle('EndActivityConversation', array(&$this, &$xs, $conv));
}
$replyProfiles = array();
$reply_ids = $this->getReplies(); $reply_ids = $this->getReplies();
foreach ($reply_ids as $id) { foreach ($reply_ids as $id) {
$profile = Profile::staticGet('id', $id); $profile = Profile::staticGet('id', $id);
if (!empty($profile)) { if (!empty($profile)) {
$xs->element( $replyProfiles[] = $profile;
'link', array(
'rel' => 'ostatus:attention',
'href' => $profile->getUri()
)
);
} }
} }
if (Event::handle('StartActivityAttentionProfiles', array(&$this, &$xs, &$replyProfiles))) {
foreach ($replyProfiles as $profile) {
$xs->element('link', array('rel' => 'ostatus:attention',
'href' => $profile->getUri()));
$xs->element('link', array('rel' => 'mentioned',
'href' => $profile->getUri()));
}
Event::handle('EndActivityAttentionProfiles', array(&$this, &$xs, $replyProfiles));
}
$groups = $this->getGroups(); $groups = $this->getGroups();
foreach ($groups as $group) { if (Event::handle('StartActivityAttentionGroups', array(&$this, &$xs, &$groups))) {
$xs->element( foreach ($groups as $group) {
'link', array( $xs->element('link', array('rel' => 'ostatus:attention',
'rel' => 'ostatus:attention', 'href' => $group->permalink()));
'href' => $group->permalink() $xs->element('link', array('rel' => 'mentioned',
) 'href' => $group->permalink()));
); }
Event::handle('EndActivityAttentionGroups', array(&$this, &$xs, $groups));
} }
$repeat = null;
if (!empty($this->repeat_of)) { if (!empty($this->repeat_of)) {
$repeat = Notice::staticGet('id', $this->repeat_of); $repeat = Notice::staticGet('id', $this->repeat_of);
}
if (Event::handle('StartActivityForward', array(&$this, &$xs, &$repeat))) {
if (!empty($repeat)) { if (!empty($repeat)) {
$xs->element( $xs->element('ostatus:forward',
'ostatus:forward', array('ref' => $repeat->uri,
array('ref' => $repeat->uri, 'href' => $repeat->bestUrl()) 'href' => $repeat->bestUrl()));
);
} }
Event::handle('EndActivityForward', array(&$this, &$xs, $repeat));
} }
$xs->element( $tags = $this->getTags();
'content',
array('type' => 'html'),
common_xml_safe_str($this->rendered)
);
$tag = new Notice_tag(); if (Event::handle('StartActivityCategories', array(&$this, &$xs, &$tags))) {
$tag->notice_id = $this->id; foreach ($tags as $tag) {
if ($tag->find()) { $xs->element('category', array('term' => $tag));
while ($tag->fetch()) {
$xs->element('category', array('term' => $tag->tag));
} }
Event::handle('EndActivityCategories', array(&$this, &$xs, $tags));
} }
$tag->free();
# Enclosures // Enclosures
$enclosures = array();
$attachments = $this->attachments(); $attachments = $this->attachments();
if($attachments){
foreach($attachments as $attachment){ foreach ($attachments as $attachment) {
$enclosure=$attachment->getEnclosure(); $enclosure = $attachment->getEnclosure();
if ($enclosure) { if ($enclosure) {
$attributes = array('rel'=>'enclosure','href'=>$enclosure->url,'type'=>$enclosure->mimetype,'length'=>$enclosure->size); $enclosures[] = $enclosure;
if($enclosure->title){
$attributes['title']=$enclosure->title;
}
$xs->element('link', $attributes, null);
}
} }
} }
if (!empty($this->lat) && !empty($this->lon)) { if (Event::handle('StartActivityEnclosures', array(&$this, &$xs, &$enclosures))) {
$xs->element('georss:point', null, $this->lat . ' ' . $this->lon); foreach ($enclosures as $enclosure) {
$attributes = array('rel' => 'enclosure',
'href' => $enclosure->url,
'type' => $enclosure->mimetype,
'length' => $enclosure->size);
if ($enclosure->title) {
$attributes['title'] = $enclosure->title;
}
$xs->element('link', $attributes, null);
}
Event::handle('EndActivityEnclosures', array(&$this, &$xs, $enclosures));
} }
$xs->elementEnd('entry'); $lat = $this->lat;
$lon = $this->lon;
if (Event::handle('StartActivityGeo', array(&$this, &$xs, &$lat, &$lon))) {
if (!empty($lat) && !empty($lon)) {
$xs->element('georss:point', null, $lat . ' ' . $lon);
}
Event::handle('EndActivityGeo', array(&$this, &$xs, $lat, $lon));
}
if (Event::handle('StartActivityEnd', array(&$this, &$xs))) {
$xs->elementEnd('entry');
Event::handle('EndActivityEnd', array(&$this, &$xs));
}
return $xs->getString(); return $xs->getString();
} }
@ -1895,4 +2060,24 @@ class Notice extends Memcached_DataObject
$this->is_local == Notice::LOCAL_NONPUBLIC); $this->is_local == Notice::LOCAL_NONPUBLIC);
} }
public function getTags()
{
$tags = array();
$tag = new Notice_tag();
$tag->notice_id = $this->id;
if ($tag->find()) {
while ($tag->fetch()) {
$tags[] = $tag->tag;
}
}
$tag->free();
return $tags;
}
static private function utcDate($dt)
{
$dateStr = date('d F Y H:i:s', strtotime($dt));
$d = new DateTime($dateStr, new DateTimeZone('UTC'));
return $d->format(DATE_W3C);
}
} }

View File

@ -152,17 +152,16 @@ class Profile extends Memcached_DataObject
* *
* @return mixed Notice or null * @return mixed Notice or null
*/ */
function getCurrentNotice() function getCurrentNotice()
{ {
$notice = new Notice(); $notice = $this->getNotices(0, 1);
$notice->profile_id = $this->id;
// @fixme change this to sort on notice.id only when indexes are updated if ($notice->fetch()) {
$notice->orderBy('created DESC, notice.id DESC');
$notice->limit(1);
if ($notice->find(true)) {
return $notice; return $notice;
} else {
return null;
} }
return null;
} }
function getTaggedNotices($tag, $offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $max_id=0) function getTaggedNotices($tag, $offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $max_id=0)
@ -735,14 +734,18 @@ class Profile extends Memcached_DataObject
'role' => $name)); 'role' => $name));
if (empty($role)) { if (empty($role)) {
throw new Exception('Cannot revoke role "'.$name.'" for user #'.$this->id.'; does not exist.'); // 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));
} }
$result = $role->delete(); $result = $role->delete();
if (!$result) { if (!$result) {
common_log_db_error($role, 'DELETE', __FILE__); common_log_db_error($role, 'DELETE', __FILE__);
throw new Exception('Cannot revoke role "'.$name.'" for user #'.$this->id.'; database error.'); // 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));
} }
return true; return true;
@ -943,4 +946,20 @@ class Profile extends Memcached_DataObject
return $result; return $result;
} }
function getAtomFeed()
{
$feed = null;
if (Event::handle('StartProfileGetAtomFeed', array($this, &$feed))) {
$user = User::staticGet('id', $this->id);
if (!empty($user)) {
$feed = common_local_url('ApiTimelineUser', array('id' => $user->id,
'format' => 'atom'));
}
Event::handle('EndProfileGetAtomFeed', array($this, $feed));
}
return $feed;
}
} }

View File

@ -50,7 +50,8 @@ class Remote_profile extends Memcached_DataObject
if ($profile) { if ($profile) {
return $profile->hasright($right); return $profile->hasright($right);
} else { } else {
throw new Exception("Missing profile"); // TRANS: Exception thrown when a right for a non-existing user profile is checked.
throw new Exception(_("Missing profile."));
} }
} }
} }

View File

@ -116,6 +116,7 @@ class Safe_DataObject extends DB_DataObject
if ($this->_call($method, $params, $return)) { if ($this->_call($method, $params, $return)) {
return $return; return $return;
} else { } else {
// Low level exception. No need for i18n as discussed with Brion.
throw new Exception('Call to undefined method ' . throw new Exception('Call to undefined method ' .
get_class($this) . '::' . $method); get_class($this) . '::' . $method);
} }
@ -136,7 +137,6 @@ class Safe_DataObject extends DB_DataObject
*/ */
function databaseStructure() function databaseStructure()
{ {
global $_DB_DATAOBJECT; global $_DB_DATAOBJECT;
// Assignment code // Assignment code
@ -178,8 +178,6 @@ class Safe_DataObject extends DB_DataObject
} }
if (!$this->_database) { if (!$this->_database) {
$this->_connect(); $this->_connect();
} }
@ -205,7 +203,6 @@ class Safe_DataObject extends DB_DataObject
return true; return true;
} }
if (empty($_DB_DATAOBJECT['CONFIG'])) { if (empty($_DB_DATAOBJECT['CONFIG'])) {
DB_DataObject::_loadConfig(); DB_DataObject::_loadConfig();
} }
@ -223,7 +220,6 @@ class Safe_DataObject extends DB_DataObject
explode(PATH_SEPARATOR,$_DB_DATAOBJECT['CONFIG']["ini_{$this->_database}"]); explode(PATH_SEPARATOR,$_DB_DATAOBJECT['CONFIG']["ini_{$this->_database}"]);
} }
/* BEGIN CHANGED FROM UPSTREAM */ /* BEGIN CHANGED FROM UPSTREAM */
$_DB_DATAOBJECT['INI'][$this->_database] = $this->parseIniFiles($schemas); $_DB_DATAOBJECT['INI'][$this->_database] = $this->parseIniFiles($schemas);
/* END CHANGED FROM UPSTREAM */ /* END CHANGED FROM UPSTREAM */
@ -245,7 +241,8 @@ class Safe_DataObject extends DB_DataObject
} }
$this->debug("Cant find database schema: {$this->_database}/{$this->__table} \n". $this->debug("Cant find database schema: {$this->_database}/{$this->__table} \n".
"in links file data: " . print_r($_DB_DATAOBJECT['INI'],true),"databaseStructure",5); "in links file data: " . print_r($_DB_DATAOBJECT['INI'],true),"databaseStructure",5);
// we have to die here!! - it causes chaos if we dont (including looping forever!) // we have to die here!! - it causes chaos if we don't (including looping forever!)
// Low level exception. No need for i18n as discussed with Brion.
$this->raiseError( "Unable to load schema for database and table (turn debugging up to 5 for full error message)", DB_DATAOBJECT_ERROR_INVALIDARGS, PEAR_ERROR_DIE); $this->raiseError( "Unable to load schema for database and table (turn debugging up to 5 for full error message)", DB_DATAOBJECT_ERROR_INVALIDARGS, PEAR_ERROR_DIE);
return false; return false;
} }

View File

@ -27,7 +27,8 @@ class Status_network extends Safe_DataObject
/* the code below is auto generated do not remove the above tag */ /* the code below is auto generated do not remove the above tag */
public $__table = 'status_network'; // table name public $__table = 'status_network'; // table name
public $nickname; // varchar(64) primary_key not_null public $site_id; // int(4) primary_key not_null
public $nickname; // varchar(64) unique_key not_null
public $hostname; // varchar(255) unique_key public $hostname; // varchar(255) unique_key
public $pathname; // varchar(255) unique_key public $pathname; // varchar(255) unique_key
public $dbhost; // varchar(255) public $dbhost; // varchar(255)
@ -39,7 +40,6 @@ class Status_network extends Safe_DataObject
public $logo; // varchar(255) public $logo; // varchar(255)
public $created; // datetime() not_null public $created; // datetime() not_null
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
public $tags; // text
/* Static get */ /* Static get */
function staticGet($k,$v=NULL) { function staticGet($k,$v=NULL) {
@ -308,7 +308,61 @@ class Status_network extends Safe_DataObject
*/ */
function getTags() function getTags()
{ {
return array_filter(explode("|", strval($this->tags))); $result = array();
$tags = new Status_network_tag();
$tags->site_id = $this->site_id;
if ($tags->find()) {
while ($tags->fetch()) {
$result[] = $tags->tag;
}
}
// XXX : for backwards compatibility
if (empty($result)) {
return explode('|', $this->tags);
}
return $result;
}
/**
* Save a given set of tags
* @param array tags
*/
function setTags($tags)
{
$this->clearTags();
foreach ($tags as $tag) {
if (!empty($tag)) {
$snt = new Status_network_tag();
$snt->site_id = $this->site_id;
$snt->tag = $tag;
$snt->created = common_sql_now();
$id = $snt->insert();
if (!$id) {
// TRANS: Exception thrown when a tag cannot be saved.
throw new Exception(_("Unable to save tag."));
}
}
}
return true;
}
function clearTags()
{
$tag = new Status_network_tag();
$tag->site_id = $this->site_id;
if ($tag->find()) {
while($tag->fetch()) {
$tag->delete();
}
}
$tag->free();
} }
/** /**

View File

@ -0,0 +1,69 @@
<?php
/*
* StatusNet - the distributed open-source microblogging tool
* Copyright (C) 2008, 2009, 2010 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')) { exit(1); }
class Status_network_tag extends Safe_DataObject
{
###START_AUTOCODE
/* the code below is auto generated do not remove the above tag */
public $__table = 'status_network_tag'; // table name
public $site_id; // int(4) primary_key not_null
public $tag; // varchar(64) primary_key not_null
public $created; // datetime() not_null
function __construct()
{
global $config;
global $_DB_DATAOBJECT;
$sn = new Status_network();
$sn->_connect();
$config['db']['table_'. $this->__table] = $sn->_database;
$this->_connect();
}
/* Static get */
function staticGet($k,$v=null)
{
$i = DB_DataObject::staticGet('Status_network_tag',$k,$v);
// Don't use local process cache; if we're fetching multiple
// times it's because we're reloading it in a long-running
// process; we need a fresh copy!
global $_DB_DATAOBJECT;
unset($_DB_DATAOBJECT['CACHE']['status_network_tag']);
return $i;
}
/* the code above is auto generated do not remove the tag below */
###END_AUTOCODE
function pkeyGet($kv)
{
return Memcached_DataObject::pkeyGet('Status_network_tag', $kv);
}
}

View File

@ -71,14 +71,17 @@ class Subscription extends Memcached_DataObject
} }
if (!$subscriber->hasRight(Right::SUBSCRIBE)) { if (!$subscriber->hasRight(Right::SUBSCRIBE)) {
// TRANS: Exception thrown when trying to subscribe while being banned from subscribing.
throw new Exception(_('You have been banned from subscribing.')); throw new Exception(_('You have been banned from subscribing.'));
} }
if (self::exists($subscriber, $other)) { if (self::exists($subscriber, $other)) {
// TRANS: Exception thrown when trying to subscribe while already subscribed.
throw new Exception(_('Already subscribed!')); throw new Exception(_('Already subscribed!'));
} }
if ($other->hasBlocked($subscriber)) { if ($other->hasBlocked($subscriber)) {
// TRANS: Exception thrown when trying to subscribe to a user who has blocked the subscribing user.
throw new Exception(_('User has blocked you.')); throw new Exception(_('User has blocked you.'));
} }
@ -129,6 +132,7 @@ class Subscription extends Memcached_DataObject
if (!$result) { if (!$result) {
common_log_db_error($sub, 'INSERT', __FILE__); common_log_db_error($sub, 'INSERT', __FILE__);
// TRANS: Exception thrown when a subscription could not be stored on the server.
throw new Exception(_('Could not save subscription.')); throw new Exception(_('Could not save subscription.'));
} }
@ -160,17 +164,18 @@ class Subscription extends Memcached_DataObject
* Cancel a subscription * Cancel a subscription
* *
*/ */
function cancel($subscriber, $other) function cancel($subscriber, $other)
{ {
if (!self::exists($subscriber, $other)) { if (!self::exists($subscriber, $other)) {
// TRANS: Exception thrown when trying to unsibscribe without a subscription.
throw new Exception(_('Not subscribed!')); throw new Exception(_('Not subscribed!'));
} }
// Don't allow deleting self subs // Don't allow deleting self subs
if ($subscriber->id == $other->id) { if ($subscriber->id == $other->id) {
throw new Exception(_('Couldn\'t delete self-subscription.')); // TRANS: Exception thrown when trying to unsubscribe a user from themselves.
throw new Exception(_('Could not delete self-subscription.'));
} }
if (Event::handle('StartUnsubscribe', array($subscriber, $other))) { if (Event::handle('StartUnsubscribe', array($subscriber, $other))) {
@ -197,7 +202,8 @@ class Subscription extends Memcached_DataObject
if (!$result) { if (!$result) {
common_log_db_error($token, 'DELETE', __FILE__); common_log_db_error($token, 'DELETE', __FILE__);
throw new Exception(_('Couldn\'t delete subscription OMB token.')); // TRANS: Exception thrown when the OMB token for a subscription could not deleted on the server.
throw new Exception(_('Could not delete subscription OMB token.'));
} }
} else { } else {
common_log(LOG_ERR, "Couldn't find credentials with token {$token->tok}"); common_log(LOG_ERR, "Couldn't find credentials with token {$token->tok}");
@ -208,7 +214,8 @@ class Subscription extends Memcached_DataObject
if (!$result) { if (!$result) {
common_log_db_error($sub, 'DELETE', __FILE__); common_log_db_error($sub, 'DELETE', __FILE__);
throw new Exception(_('Couldn\'t delete subscription.')); // TRANS: Exception thrown when a subscription could not be deleted on the server.
throw new Exception(_('Could not delete subscription.'));
} }
self::blow('user:notices_with_friends:%d', $subscriber->id); self::blow('user:notices_with_friends:%d', $subscriber->id);

View File

@ -355,11 +355,12 @@ class User extends Memcached_DataObject
__FILE__); __FILE__);
} else { } else {
$notice = Notice::saveNew($welcomeuser->id, $notice = Notice::saveNew($welcomeuser->id,
// TRANS: Notice given on user registration.
// TRANS: %1$s is the sitename, $2$s is the registering user's nickname.
sprintf(_('Welcome to %1$s, @%2$s!'), sprintf(_('Welcome to %1$s, @%2$s!'),
common_config('site', 'name'), common_config('site', 'name'),
$user->nickname), $user->nickname),
'system'); 'system');
} }
} }
@ -370,7 +371,6 @@ class User extends Memcached_DataObject
} }
// Things we do when the email changes // Things we do when the email changes
function emailChanged() function emailChanged()
{ {
@ -519,7 +519,7 @@ class User extends Memcached_DataObject
if ($this->id == $other->id) { if ($this->id == $other->id) {
common_log(LOG_WARNING, common_log(LOG_WARNING,
sprintf( sprintf(
"Profile ID %d (%s) tried to block his or herself.", "Profile ID %d (%s) tried to block themself.",
$this->id, $this->id,
$this->nickname $this->nickname
) )

View File

@ -492,6 +492,7 @@ class User_group extends Memcached_DataObject
if (!$result) { if (!$result) {
common_log_db_error($group, 'INSERT', __FILE__); common_log_db_error($group, 'INSERT', __FILE__);
// TRANS: Server exception thrown when creating a group failed.
throw new ServerException(_('Could not create group.')); throw new ServerException(_('Could not create group.'));
} }
@ -501,6 +502,7 @@ class User_group extends Memcached_DataObject
$result = $group->update($orig); $result = $group->update($orig);
if (!$result) { if (!$result) {
common_log_db_error($group, 'UPDATE', __FILE__); common_log_db_error($group, 'UPDATE', __FILE__);
// TRANS: Server exception thrown when updating a group URI failed.
throw new ServerException(_('Could not set group URI.')); throw new ServerException(_('Could not set group URI.'));
} }
} }
@ -508,6 +510,7 @@ class User_group extends Memcached_DataObject
$result = $group->setAliases($aliases); $result = $group->setAliases($aliases);
if (!$result) { if (!$result) {
// TRANS: Server exception thrown when creating group aliases failed.
throw new ServerException(_('Could not create aliases.')); throw new ServerException(_('Could not create aliases.'));
} }
@ -522,6 +525,7 @@ class User_group extends Memcached_DataObject
if (!$result) { if (!$result) {
common_log_db_error($member, 'INSERT', __FILE__); common_log_db_error($member, 'INSERT', __FILE__);
// TRANS: Server exception thrown when setting group membership failed.
throw new ServerException(_('Could not set group membership.')); throw new ServerException(_('Could not set group membership.'));
} }
@ -536,6 +540,7 @@ class User_group extends Memcached_DataObject
if (!$result) { if (!$result) {
common_log_db_error($local_group, 'INSERT', __FILE__); common_log_db_error($local_group, 'INSERT', __FILE__);
// TRANS: Server exception thrown when saving local group information failed.
throw new ServerException(_('Could not save local group info.')); throw new ServerException(_('Could not save local group info.'));
} }
} }

View File

@ -1,4 +1,5 @@
[status_network] [status_network]
site_id = 129
nickname = 130 nickname = 130
hostname = 2 hostname = 2
pathname = 2 pathname = 2
@ -11,9 +12,19 @@ theme = 2
logo = 2 logo = 2
created = 142 created = 142
modified = 384 modified = 384
tags = 34
[status_network__keys] [status_network__keys]
nickname = K site_id = K
nickname = U
hostname = U hostname = U
pathname = U pathname = U
[status_network_tag]
site_id = 129
tag = 130
created = 142
[status_network_tag__keys]
site_id = K
tag = K

View File

@ -51,6 +51,7 @@ VALUES
('smob','SMOB','http://smob.sioc-project.org/', now()), ('smob','SMOB','http://smob.sioc-project.org/', now()),
('socialoomphBfD4pMqz31', 'SocialOomph', 'http://www.socialoomph.com/', now()), ('socialoomphBfD4pMqz31', 'SocialOomph', 'http://www.socialoomph.com/', now()),
('spaz','Spaz','http://funkatron.com/spaz', now()), ('spaz','Spaz','http://funkatron.com/spaz', now()),
('StatusNet Desktop', 'StatusNet Desktop', 'http://status.net/desktop', now()),
('tarpipe','tarpipe','http://tarpipe.com/', now()), ('tarpipe','tarpipe','http://tarpipe.com/', now()),
('tjunar','Tjunar','http://nederflash.nl/boek/titels/tjunar-air', now()), ('tjunar','Tjunar','http://nederflash.nl/boek/titels/tjunar-air', now()),
('tr.im','tr.im','http://tr.im/', now()), ('tr.im','tr.im','http://tr.im/', now()),

View File

@ -2,7 +2,8 @@
create table status_network ( create table status_network (
nickname varchar(64) primary key comment 'nickname', site_id integer auto_increment primary key comment 'unique id',
nickname varchar(64) unique key comment 'nickname',
hostname varchar(255) unique key comment 'alternate hostname if any', hostname varchar(255) unique key comment 'alternate hostname if any',
pathname varchar(255) unique key comment 'alternate pathname if any', pathname varchar(255) unique key comment 'alternate pathname if any',
@ -21,3 +22,12 @@ create table status_network (
modified timestamp comment 'date this record was modified' modified timestamp comment 'date this record was modified'
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci; ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci;
create table status_network_tag (
site_id integer comment 'unique id',
tag varchar(64) comment 'tag name',
created datetime not null comment 'date the record was created',
constraint primary key (site_id, tag)
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci;

13
db/site_093to094.sql Normal file
View File

@ -0,0 +1,13 @@
alter table status_network
drop primary key,
add column site_id integer auto_increment primary key first,
add unique key (nickname);
create table status_network_tag (
site_id integer comment 'unique id',
tag varchar(64) comment 'tag name',
created datetime not null comment 'date the record was created',
constraint primary key (site_id, tag)
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci;

View File

@ -20,7 +20,7 @@
/** /**
* The library version string * The library version string
*/ */
define('Auth_OpenID_VERSION', '2.1.3'); define('Auth_OpenID_VERSION', '2.2.2');
/** /**
* Require the fetcher code. * Require the fetcher code.
@ -102,9 +102,7 @@ define('Auth_OpenID_digits',
define('Auth_OpenID_punct', define('Auth_OpenID_punct',
"!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"); "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~");
if (Auth_OpenID_getMathLib() === null) { Auth_OpenID_include_init();
Auth_OpenID_setNoMathSupport();
}
/** /**
* The OpenID utility function class. * The OpenID utility function class.
@ -120,7 +118,7 @@ class Auth_OpenID {
* *
* @access private * @access private
*/ */
function isFailure($thing) static function isFailure($thing)
{ {
return is_a($thing, 'Auth_OpenID_FailureResponse'); return is_a($thing, 'Auth_OpenID_FailureResponse');
} }
@ -139,9 +137,12 @@ class Auth_OpenID {
* Returns an empty array if neither GET nor POST was used, or if * Returns an empty array if neither GET nor POST was used, or if
* POST was used but php://input cannot be opened. * POST was used but php://input cannot be opened.
* *
* See background:
* http://lists.openidenabled.com/pipermail/dev/2007-March/000395.html
*
* @access private * @access private
*/ */
function getQuery($query_str=null) static function getQuery($query_str=null)
{ {
$data = array(); $data = array();
@ -177,7 +178,7 @@ class Auth_OpenID {
return $data; return $data;
} }
function params_from_string($str) static function params_from_string($str)
{ {
$chunks = explode("&", $str); $chunks = explode("&", $str);
@ -190,7 +191,7 @@ class Auth_OpenID {
} }
list($k, $v) = $parts; list($k, $v) = $parts;
$data[$k] = urldecode($v); $data[urldecode($k)] = urldecode($v);
} }
return $data; return $data;
@ -203,7 +204,7 @@ class Auth_OpenID {
* *
* @access private * @access private
*/ */
function ensureDir($dir_name) static function ensureDir($dir_name)
{ {
if (is_dir($dir_name) || @mkdir($dir_name)) { if (is_dir($dir_name) || @mkdir($dir_name)) {
return true; return true;
@ -225,7 +226,7 @@ class Auth_OpenID {
* *
* @access private * @access private
*/ */
function addPrefix($values, $prefix) static function addPrefix($values, $prefix)
{ {
$new_values = array(); $new_values = array();
foreach ($values as $s) { foreach ($values as $s) {
@ -241,7 +242,7 @@ class Auth_OpenID {
* *
* @access private * @access private
*/ */
function arrayGet($arr, $key, $fallback = null) static function arrayGet($arr, $key, $fallback = null)
{ {
if (is_array($arr)) { if (is_array($arr)) {
if (array_key_exists($key, $arr)) { if (array_key_exists($key, $arr)) {
@ -261,7 +262,7 @@ class Auth_OpenID {
/** /**
* Replacement for PHP's broken parse_str. * Replacement for PHP's broken parse_str.
*/ */
function parse_str($query) static function parse_str($query)
{ {
if ($query === null) { if ($query === null) {
return null; return null;
@ -278,7 +279,7 @@ class Auth_OpenID {
} }
list($key, $value) = $pair; list($key, $value) = $pair;
$new_parts[$key] = urldecode($value); $new_parts[urldecode($key)] = urldecode($value);
} }
return $new_parts; return $new_parts;
@ -295,7 +296,7 @@ class Auth_OpenID {
* pairs from $data into a URL query string * pairs from $data into a URL query string
* (e.g. "username=bob&id=56"). * (e.g. "username=bob&id=56").
*/ */
function httpBuildQuery($data) static function httpBuildQuery($data)
{ {
$pairs = array(); $pairs = array();
foreach ($data as $key => $value) { foreach ($data as $key => $value) {
@ -323,7 +324,7 @@ class Auth_OpenID {
* @return string $url The original URL with the new parameters added. * @return string $url The original URL with the new parameters added.
* *
*/ */
function appendArgs($url, $args) static function appendArgs($url, $args)
{ {
if (count($args) == 0) { if (count($args) == 0) {
return $url; return $url;
@ -367,7 +368,7 @@ class Auth_OpenID {
* @return string $url The URL resulting from assembling the * @return string $url The URL resulting from assembling the
* specified components. * specified components.
*/ */
function urlunparse($scheme, $host, $port = null, $path = '/', static function urlunparse($scheme, $host, $port = null, $path = '/',
$query = '', $fragment = '') $query = '', $fragment = '')
{ {
@ -412,7 +413,7 @@ class Auth_OpenID {
* @return mixed $new_url The URL after normalization, or null if * @return mixed $new_url The URL after normalization, or null if
* $url was malformed. * $url was malformed.
*/ */
function normalizeUrl($url) static function normalizeUrl($url)
{ {
@$parsed = parse_url($url); @$parsed = parse_url($url);
@ -443,7 +444,7 @@ class Auth_OpenID {
* *
* @access private * @access private
*/ */
function intval($value) static function intval($value)
{ {
$re = "/^\\d+$/"; $re = "/^\\d+$/";
@ -461,7 +462,7 @@ class Auth_OpenID {
* @param string $str The string of bytes to count. * @param string $str The string of bytes to count.
* @return int The number of bytes in $str. * @return int The number of bytes in $str.
*/ */
function bytes($str) static function bytes($str)
{ {
return strlen(bin2hex($str)) / 2; return strlen(bin2hex($str)) / 2;
} }
@ -470,7 +471,7 @@ class Auth_OpenID {
* Get the bytes in a string independently of multibyte support * Get the bytes in a string independently of multibyte support
* conditions. * conditions.
*/ */
function toBytes($str) static function toBytes($str)
{ {
$hex = bin2hex($str); $hex = bin2hex($str);
@ -486,7 +487,7 @@ class Auth_OpenID {
return $b; return $b;
} }
function urldefrag($url) static function urldefrag($url)
{ {
$parts = explode("#", $url, 2); $parts = explode("#", $url, 2);
@ -497,7 +498,7 @@ class Auth_OpenID {
} }
} }
function filter($callback, &$sequence) static function filter($callback, &$sequence)
{ {
$result = array(); $result = array();
@ -510,7 +511,7 @@ class Auth_OpenID {
return $result; return $result;
} }
function update(&$dest, &$src) static function update(&$dest, &$src)
{ {
foreach ($src as $k => $v) { foreach ($src as $k => $v) {
$dest[$k] = $v; $dest[$k] = $v;
@ -524,14 +525,14 @@ class Auth_OpenID {
* *
* @param string $format_string The sprintf format for the message * @param string $format_string The sprintf format for the message
*/ */
function log($format_string) static function log($format_string)
{ {
$args = func_get_args(); $args = func_get_args();
$message = call_user_func_array('sprintf', $args); $message = call_user_func_array('sprintf', $args);
error_log($message); error_log($message);
} }
function autoSubmitHTML($form, $title="OpenId transaction in progress") static function autoSubmitHTML($form, $title="OpenId transaction in progress")
{ {
return("<html>". return("<html>".
"<head><title>". "<head><title>".
@ -549,4 +550,14 @@ class Auth_OpenID {
"</html>"); "</html>");
} }
} }
?>
/*
* Function to run when this file is included.
* Abstracted to a function to make life easier
* for some PHP optimizers.
*/
function Auth_OpenID_include_init() {
if (Auth_OpenID_getMathLib() === null) {
Auth_OpenID_setNoMathSupport();
}
}

View File

@ -38,7 +38,7 @@ class Auth_OpenID_AX {
* @return bool true if $thing is an Auth_OpenID_AX_Error; false * @return bool true if $thing is an Auth_OpenID_AX_Error; false
* if not. * if not.
*/ */
function isError($thing) static function isError($thing)
{ {
return is_a($thing, 'Auth_OpenID_AX_Error'); return is_a($thing, 'Auth_OpenID_AX_Error');
} }
@ -191,7 +191,7 @@ class Auth_OpenID_AX_AttrInfo {
* Construct an attribute information object. For parameter * Construct an attribute information object. For parameter
* details, see the constructor. * details, see the constructor.
*/ */
function make($type_uri, $count=1, $required=false, static function make($type_uri, $count=1, $required=false,
$alias=null) $alias=null)
{ {
if ($alias !== null) { if ($alias !== null) {
@ -235,7 +235,7 @@ class Auth_OpenID_AX_AttrInfo {
* return null If an alias is present in the list of aliases but * return null If an alias is present in the list of aliases but
* is not present in the namespace map. * is not present in the namespace map.
*/ */
function Auth_OpenID_AX_toTypeURIs(&$namespace_map, $alias_list_s) function Auth_OpenID_AX_toTypeURIs($namespace_map, $alias_list_s)
{ {
$uris = array(); $uris = array();
@ -386,7 +386,7 @@ class Auth_OpenID_AX_FetchRequest extends Auth_OpenID_AX_Message {
* Auth_OpenID_AX_FetchRequest extracted from the request message if * Auth_OpenID_AX_FetchRequest extracted from the request message if
* successful * successful
*/ */
function &fromOpenIDRequest($request) static function fromOpenIDRequest($request)
{ {
$m = $request->message; $m = $request->message;
$obj = new Auth_OpenID_AX_FetchRequest(); $obj = new Auth_OpenID_AX_FetchRequest();
@ -484,7 +484,7 @@ class Auth_OpenID_AX_FetchRequest extends Auth_OpenID_AX_Message {
Auth_OpenID::arrayGet($ax_args, 'required')); Auth_OpenID::arrayGet($ax_args, 'required'));
foreach ($required as $type_uri) { foreach ($required as $type_uri) {
$attrib =& $this->requested_attributes[$type_uri]; $attrib = $this->requested_attributes[$type_uri];
$attrib->required = true; $attrib->required = true;
} }
@ -587,7 +587,7 @@ class Auth_OpenID_AX_KeyValueMessage extends Auth_OpenID_AX_Message {
* *
* @access private * @access private
*/ */
function _getExtensionKVArgs(&$aliases) function _getExtensionKVArgs($aliases)
{ {
if ($aliases === null) { if ($aliases === null) {
$aliases = new Auth_OpenID_NamespaceMap(); $aliases = new Auth_OpenID_NamespaceMap();
@ -652,7 +652,7 @@ class Auth_OpenID_AX_KeyValueMessage extends Auth_OpenID_AX_Message {
foreach ($aliases->iteritems() as $pair) { foreach ($aliases->iteritems() as $pair) {
list($type_uri, $alias) = $pair; list($type_uri, $alias) = $pair;
if (array_key_exists('count.' . $alias, $ax_args)) { if (array_key_exists('count.' . $alias, $ax_args) && ($ax_args['count.' . $alias] !== Auth_OpenID_AX_UNLIMITED_VALUES)) {
$count_key = 'count.' . $alias; $count_key = 'count.' . $alias;
$count_s = $ax_args[$count_key]; $count_s = $ax_args[$count_key];
@ -888,7 +888,7 @@ class Auth_OpenID_AX_FetchResponse extends Auth_OpenID_AX_KeyValueMessage {
$ax_args['update_url'] = $update_url; $ax_args['update_url'] = $update_url;
} }
Auth_OpenID::update(&$ax_args, $kv_args); Auth_OpenID::update($ax_args, $kv_args);
return $ax_args; return $ax_args;
} }
@ -922,7 +922,7 @@ class Auth_OpenID_AX_FetchResponse extends Auth_OpenID_AX_KeyValueMessage {
* @return $response A FetchResponse containing the data from the * @return $response A FetchResponse containing the data from the
* OpenID message * OpenID message
*/ */
function fromSuccessResponse($success_response, $signed=true) static function fromSuccessResponse($success_response, $signed=true)
{ {
$obj = new Auth_OpenID_AX_FetchResponse(); $obj = new Auth_OpenID_AX_FetchResponse();
if ($signed) { if ($signed) {
@ -960,7 +960,7 @@ class Auth_OpenID_AX_StoreRequest extends Auth_OpenID_AX_KeyValueMessage {
{ {
$ax_args = $this->_newArgs(); $ax_args = $this->_newArgs();
$kv_args = $this->_getExtensionKVArgs($aliases); $kv_args = $this->_getExtensionKVArgs($aliases);
Auth_OpenID::update(&$ax_args, $kv_args); Auth_OpenID::update($ax_args, $kv_args);
return $ax_args; return $ax_args;
} }
} }
@ -980,7 +980,7 @@ class Auth_OpenID_AX_StoreResponse extends Auth_OpenID_AX_Message {
* Returns Auth_OpenID_AX_Error on error or an * Returns Auth_OpenID_AX_Error on error or an
* Auth_OpenID_AX_StoreResponse object on success. * Auth_OpenID_AX_StoreResponse object on success.
*/ */
function &make($succeeded=true, $error_message=null) function make($succeeded=true, $error_message=null)
{ {
if (($succeeded) && ($error_message !== null)) { if (($succeeded) && ($error_message !== null)) {
return new Auth_OpenID_AX_Error('An error message may only be '. return new Auth_OpenID_AX_Error('An error message may only be '.
@ -1020,4 +1020,3 @@ class Auth_OpenID_AX_StoreResponse extends Auth_OpenID_AX_Message {
} }
} }
?>

View File

@ -94,7 +94,7 @@ class Auth_OpenID_Association {
* @return association An {@link Auth_OpenID_Association} * @return association An {@link Auth_OpenID_Association}
* instance. * instance.
*/ */
function fromExpiresIn($expires_in, $handle, $secret, $assoc_type) static function fromExpiresIn($expires_in, $handle, $secret, $assoc_type)
{ {
$issued = time(); $issued = time();
$lifetime = $expires_in; $lifetime = $expires_in;
@ -132,7 +132,7 @@ class Auth_OpenID_Association {
$handle, $secret, $issued, $lifetime, $assoc_type) $handle, $secret, $issued, $lifetime, $assoc_type)
{ {
if (!in_array($assoc_type, if (!in_array($assoc_type,
Auth_OpenID_getSupportedAssociationTypes())) { Auth_OpenID_getSupportedAssociationTypes(), true)) {
$fmt = 'Unsupported association type (%s)'; $fmt = 'Unsupported association type (%s)';
trigger_error(sprintf($fmt, $assoc_type), E_USER_ERROR); trigger_error(sprintf($fmt, $assoc_type), E_USER_ERROR);
} }
@ -206,7 +206,7 @@ class Auth_OpenID_Association {
* @param string $assoc_s Association as serialized by serialize() * @param string $assoc_s Association as serialized by serialize()
* @return Auth_OpenID_Association $result instance of this class * @return Auth_OpenID_Association $result instance of this class
*/ */
function deserialize($class_name, $assoc_s) static function deserialize($class_name, $assoc_s)
{ {
$pairs = Auth_OpenID_KVForm::toArray($assoc_s, $strict = true); $pairs = Auth_OpenID_KVForm::toArray($assoc_s, $strict = true);
$keys = array(); $keys = array();
@ -327,7 +327,7 @@ class Auth_OpenID_Association {
* *
* @access private * @access private
*/ */
function _makePairs(&$message) function _makePairs($message)
{ {
$signed = $message->getArg(Auth_OpenID_OPENID_NS, 'signed'); $signed = $message->getArg(Auth_OpenID_OPENID_NS, 'signed');
if (!$signed || Auth_OpenID::isFailure($signed)) { if (!$signed || Auth_OpenID::isFailure($signed)) {
@ -352,7 +352,7 @@ class Auth_OpenID_Association {
* *
* @access private * @access private
*/ */
function getMessageSignature(&$message) function getMessageSignature($message)
{ {
$pairs = $this->_makePairs($message); $pairs = $this->_makePairs($message);
return base64_encode($this->sign($pairs)); return base64_encode($this->sign($pairs));
@ -364,7 +364,7 @@ class Auth_OpenID_Association {
* *
* @access private * @access private
*/ */
function checkMessageSignature(&$message) function checkMessageSignature($message)
{ {
$sig = $message->getArg(Auth_OpenID_OPENID_NS, $sig = $message->getArg(Auth_OpenID_OPENID_NS,
'sig'); 'sig');
@ -374,7 +374,42 @@ class Auth_OpenID_Association {
} }
$calculated_sig = $this->getMessageSignature($message); $calculated_sig = $this->getMessageSignature($message);
return $calculated_sig == $sig;
return $this->constantTimeCompare($calculated_sig, $sig);
}
/**
* String comparison function which will complete in a constant time
* for strings of any given matching length, to help prevent an attacker
* from distinguishing how much of a signature token they have guessed
* correctly.
*
* For this usage, it's assumed that the length of the string is known,
* so we may safely short-circuit on mismatched lengths which will be known
* to be invalid by the attacker.
*
* http://lists.openid.net/pipermail/openid-security/2010-July/001156.html
* http://rdist.root.org/2010/01/07/timing-independent-array-comparison/
*/
private function constantTimeCompare($a, $b)
{
$len = strlen($a);
if (strlen($b) !== $len) {
// Short-circuit on length mismatch; attackers will already know
// the correct target length so this is safe.
return false;
}
if ($len == 0) {
// 0-length valid input shouldn't really happen. :)
return true;
}
$result = 0;
for ($i = 0; $i < strlen($a); $i++) {
// We use scary bitwise operations to avoid logical short-circuits
// in lower-level code.
$result |= ord($a{$i}) ^ ord($b{$i});
}
return ($result == 0);
} }
} }
@ -469,18 +504,16 @@ function Auth_OpenID_getOnlyEncryptedOrder()
return $result; return $result;
} }
function &Auth_OpenID_getDefaultNegotiator() function Auth_OpenID_getDefaultNegotiator()
{ {
$x = new Auth_OpenID_SessionNegotiator( return new Auth_OpenID_SessionNegotiator(
Auth_OpenID_getDefaultAssociationOrder()); Auth_OpenID_getDefaultAssociationOrder());
return $x;
} }
function &Auth_OpenID_getEncryptedNegotiator() function Auth_OpenID_getEncryptedNegotiator()
{ {
$x = new Auth_OpenID_SessionNegotiator( return new Auth_OpenID_SessionNegotiator(
Auth_OpenID_getOnlyEncryptedOrder()); Auth_OpenID_getOnlyEncryptedOrder());
return $x;
} }
/** /**
@ -610,4 +643,3 @@ class Auth_OpenID_SessionNegotiator {
} }
} }
?>

View File

@ -351,8 +351,7 @@ function Auth_OpenID_math_extensions()
'class' => 'Auth_OpenID_GmpMathWrapper'); 'class' => 'Auth_OpenID_GmpMathWrapper');
} }
$result[] = array( $result[] = array('modules' => array('bcmath', 'php_bcmath'),
'modules' => array('bcmath', 'php_bcmath'),
'extension' => 'bcmath', 'extension' => 'bcmath',
'class' => 'Auth_OpenID_BcMathWrapper'); 'class' => 'Auth_OpenID_BcMathWrapper');
@ -366,27 +365,9 @@ function Auth_OpenID_detectMathLibrary($exts)
{ {
$loaded = false; $loaded = false;
$hasDl = function_exists('dl');
foreach ($exts as $extension) { foreach ($exts as $extension) {
// See if the extension specified is already loaded. if (extension_loaded($extension['extension'])) {
if ($extension['extension'] &&
extension_loaded($extension['extension'])) {
$loaded = true;
}
// Try to load dynamic modules.
if (!$loaded) {
foreach ($extension['modules'] as $module) {
if (@dl($module . "." . PHP_SHLIB_SUFFIX)) {
$loaded = true;
break;
}
}
}
// If the load succeeded, supply an instance of
// Auth_OpenID_MathWrapper which wraps the specified
// module's functionality.
if ($loaded) {
return $extension; return $extension;
} }
} }
@ -405,7 +386,7 @@ function Auth_OpenID_detectMathLibrary($exts)
* instance of a wrapper for that extension module. If no extension * instance of a wrapper for that extension module. If no extension
* module is found, an instance of {@link Auth_OpenID_MathWrapper} is * module is found, an instance of {@link Auth_OpenID_MathWrapper} is
* returned, which wraps the native PHP integer implementation. The * returned, which wraps the native PHP integer implementation. The
* proper calling convention for this method is $lib =& * proper calling convention for this method is $lib =
* Auth_OpenID_getMathLib(). * Auth_OpenID_getMathLib().
* *
* This function checks for the existence of specific long number * This function checks for the existence of specific long number
@ -416,7 +397,7 @@ function Auth_OpenID_detectMathLibrary($exts)
* *
* @package OpenID * @package OpenID
*/ */
function &Auth_OpenID_getMathLib() function Auth_OpenID_getMathLib()
{ {
// The instance of Auth_OpenID_MathWrapper that we choose to // The instance of Auth_OpenID_MathWrapper that we choose to
// supply will be stored here, so that subseqent calls to this // supply will be stored here, so that subseqent calls to this
@ -468,4 +449,4 @@ function Auth_OpenID_noMathSupport()
return defined('Auth_OpenID_NO_MATH_SUPPORT'); return defined('Auth_OpenID_NO_MATH_SUPPORT');
} }
?>

View File

@ -258,19 +258,19 @@ class Auth_OpenID_Consumer {
* when creating the internal consumer object. This is used for * when creating the internal consumer object. This is used for
* testing. * testing.
*/ */
function Auth_OpenID_Consumer(&$store, $session = null, function Auth_OpenID_Consumer($store, $session = null,
$consumer_cls = null) $consumer_cls = null)
{ {
if ($session === null) { if ($session === null) {
$session = new Auth_Yadis_PHPSession(); $session = new Auth_Yadis_PHPSession();
} }
$this->session =& $session; $this->session = $session;
if ($consumer_cls !== null) { if ($consumer_cls !== null) {
$this->consumer =& new $consumer_cls($store); $this->consumer = new $consumer_cls($store);
} else { } else {
$this->consumer =& new Auth_OpenID_GenericConsumer($store); $this->consumer = new Auth_OpenID_GenericConsumer($store);
} }
$this->_token_key = $this->session_key_prefix . $this->_token_suffix; $this->_token_key = $this->session_key_prefix . $this->_token_suffix;
@ -281,7 +281,7 @@ class Auth_OpenID_Consumer {
* *
* @access private * @access private
*/ */
function getDiscoveryObject(&$session, $openid_url, function getDiscoveryObject($session, $openid_url,
$session_key_prefix) $session_key_prefix)
{ {
return new Auth_Yadis_Discovery($session, $openid_url, return new Auth_Yadis_Discovery($session, $openid_url,
@ -339,7 +339,7 @@ class Auth_OpenID_Consumer {
$this->consumer->fetcher); $this->consumer->fetcher);
// Reset the 'stale' attribute of the manager. // Reset the 'stale' attribute of the manager.
$m =& $disco->getManager(); $m = $disco->getManager();
if ($m) { if ($m) {
$m->stale = false; $m->stale = false;
$disco->session->set($disco->session_key, $disco->session->set($disco->session_key,
@ -370,7 +370,7 @@ class Auth_OpenID_Consumer {
* @return Auth_OpenID_AuthRequest $auth_request An OpenID * @return Auth_OpenID_AuthRequest $auth_request An OpenID
* authentication request object. * authentication request object.
*/ */
function &beginWithoutDiscovery($endpoint, $anonymous=false) function beginWithoutDiscovery($endpoint, $anonymous=false)
{ {
$loader = new Auth_OpenID_ServiceEndpointLoader(); $loader = new Auth_OpenID_ServiceEndpointLoader();
$auth_req = $this->consumer->begin($endpoint); $auth_req = $this->consumer->begin($endpoint);
@ -467,7 +467,7 @@ class Auth_OpenID_DiffieHellmanSHA1ConsumerSession {
function getRequest() function getRequest()
{ {
$math =& Auth_OpenID_getMathLib(); $math = Auth_OpenID_getMathLib();
$cpub = $math->longToBase64($this->dh->public); $cpub = $math->longToBase64($this->dh->public);
@ -496,7 +496,7 @@ class Auth_OpenID_DiffieHellmanSHA1ConsumerSession {
return null; return null;
} }
$math =& Auth_OpenID_getMathLib(); $math = Auth_OpenID_getMathLib();
$spub = $math->base64ToLong($response->getArg(Auth_OpenID_OPENID_NS, $spub = $math->base64ToLong($response->getArg(Auth_OpenID_OPENID_NS,
'dh_server_public')); 'dh_server_public'));
@ -611,11 +611,11 @@ class Auth_OpenID_GenericConsumer {
* in the module description. The default value is False, which * in the module description. The default value is False, which
* disables immediate mode. * disables immediate mode.
*/ */
function Auth_OpenID_GenericConsumer(&$store) function Auth_OpenID_GenericConsumer($store)
{ {
$this->store =& $store; $this->store = $store;
$this->negotiator =& Auth_OpenID_getDefaultNegotiator(); $this->negotiator = Auth_OpenID_getDefaultNegotiator();
$this->_use_assocs = ($this->store ? true : false); $this->_use_assocs = (is_null($this->store) ? false : true);
$this->fetcher = Auth_Yadis_Yadis::getHTTPFetcher(); $this->fetcher = Auth_Yadis_Yadis::getHTTPFetcher();
@ -665,14 +665,14 @@ class Auth_OpenID_GenericConsumer {
$method = Auth_OpenID::arrayGet($mode_methods, $mode, $method = Auth_OpenID::arrayGet($mode_methods, $mode,
'_completeInvalid'); '_completeInvalid');
return call_user_func_array(array(&$this, $method), return call_user_func_array(array($this, $method),
array($message, $endpoint, $return_to)); array($message, &$endpoint, $return_to));
} }
/** /**
* @access private * @access private
*/ */
function _completeInvalid($message, &$endpoint, $unused) function _completeInvalid($message, $endpoint, $unused)
{ {
$mode = $message->getArg(Auth_OpenID_OPENID_NS, 'mode', $mode = $message->getArg(Auth_OpenID_OPENID_NS, 'mode',
'<No mode set>'); '<No mode set>');
@ -684,7 +684,7 @@ class Auth_OpenID_GenericConsumer {
/** /**
* @access private * @access private
*/ */
function _complete_cancel($message, &$endpoint, $unused) function _complete_cancel($message, $endpoint, $unused)
{ {
return new Auth_OpenID_CancelResponse($endpoint); return new Auth_OpenID_CancelResponse($endpoint);
} }
@ -692,7 +692,7 @@ class Auth_OpenID_GenericConsumer {
/** /**
* @access private * @access private
*/ */
function _complete_error($message, &$endpoint, $unused) function _complete_error($message, $endpoint, $unused)
{ {
$error = $message->getArg(Auth_OpenID_OPENID_NS, 'error'); $error = $message->getArg(Auth_OpenID_OPENID_NS, 'error');
$contact = $message->getArg(Auth_OpenID_OPENID_NS, 'contact'); $contact = $message->getArg(Auth_OpenID_OPENID_NS, 'contact');
@ -705,7 +705,7 @@ class Auth_OpenID_GenericConsumer {
/** /**
* @access private * @access private
*/ */
function _complete_setup_needed($message, &$endpoint, $unused) function _complete_setup_needed($message, $endpoint, $unused)
{ {
if (!$message->isOpenID2()) { if (!$message->isOpenID2()) {
return $this->_completeInvalid($message, $endpoint); return $this->_completeInvalid($message, $endpoint);
@ -719,7 +719,7 @@ class Auth_OpenID_GenericConsumer {
/** /**
* @access private * @access private
*/ */
function _complete_id_res($message, &$endpoint, $return_to) function _complete_id_res($message, $endpoint, $return_to)
{ {
$user_setup_url = $message->getArg(Auth_OpenID_OPENID1_NS, $user_setup_url = $message->getArg(Auth_OpenID_OPENID1_NS,
'user_setup_url'); 'user_setup_url');
@ -1181,7 +1181,7 @@ class Auth_OpenID_GenericConsumer {
// oidutil.log('Performing discovery on %s' % (claimed_id,)) // oidutil.log('Performing discovery on %s' % (claimed_id,))
list($unused, $services) = call_user_func($this->discoverMethod, list($unused, $services) = call_user_func($this->discoverMethod,
$claimed_id, $claimed_id,
$this->fetcher); &$this->fetcher);
if (!$services) { if (!$services) {
return new Auth_OpenID_FailureResponse(null, return new Auth_OpenID_FailureResponse(null,
@ -1197,7 +1197,7 @@ class Auth_OpenID_GenericConsumer {
* @access private * @access private
*/ */
function _verifyDiscoveryServices($claimed_id, function _verifyDiscoveryServices($claimed_id,
&$services, &$to_match_endpoints) $services, $to_match_endpoints)
{ {
// Search the services resulting from discovery to find one // Search the services resulting from discovery to find one
// that matches the information from the assertion // that matches the information from the assertion
@ -1216,8 +1216,8 @@ class Auth_OpenID_GenericConsumer {
} }
return new Auth_OpenID_FailureResponse(null, return new Auth_OpenID_FailureResponse(null,
sprintf('No matching endpoint found after discovering %s', sprintf('No matching endpoint found after discovering %s: %s',
$claimed_id)); $claimed_id, $result->message));
} }
/** /**
@ -1397,7 +1397,7 @@ class Auth_OpenID_GenericConsumer {
* *
* @access private * @access private
*/ */
function _httpResponseToMessage($response, $server_url) static function _httpResponseToMessage($response, $server_url)
{ {
// Should this function be named Message.fromHTTPResponse instead? // Should this function be named Message.fromHTTPResponse instead?
$response_message = Auth_OpenID_Message::fromKVForm($response->body); $response_message = Auth_OpenID_Message::fromKVForm($response->body);
@ -1461,7 +1461,7 @@ class Auth_OpenID_GenericConsumer {
* *
* @access private * @access private
*/ */
function _extractSupportedAssociationType(&$server_error, &$endpoint, function _extractSupportedAssociationType($server_error, $endpoint,
$assoc_type) $assoc_type)
{ {
// Any error message whose code is not 'unsupported-type' // Any error message whose code is not 'unsupported-type'
@ -1566,7 +1566,7 @@ class Auth_OpenID_GenericConsumer {
/** /**
* @access private * @access private
*/ */
function _extractAssociation(&$assoc_response, &$assoc_session) function _extractAssociation($assoc_response, $assoc_session)
{ {
// Extract the common fields from the response, raising an // Extract the common fields from the response, raising an
// exception if they are not found // exception if they are not found
@ -1748,10 +1748,10 @@ class Auth_OpenID_AuthRequest {
* class. Instances of this class are created by the library when * class. Instances of this class are created by the library when
* needed. * needed.
*/ */
function Auth_OpenID_AuthRequest(&$endpoint, $assoc) function Auth_OpenID_AuthRequest($endpoint, $assoc)
{ {
$this->assoc = $assoc; $this->assoc = $assoc;
$this->endpoint =& $endpoint; $this->endpoint = $endpoint;
$this->return_to_args = array(); $this->return_to_args = array();
$this->message = new Auth_OpenID_Message( $this->message = new Auth_OpenID_Message(
$endpoint->preferredNamespace()); $endpoint->preferredNamespace());
@ -1764,7 +1764,7 @@ class Auth_OpenID_AuthRequest {
* $extension_request: An object that implements the extension * $extension_request: An object that implements the extension
* request interface for adding arguments to an OpenID message. * request interface for adding arguments to an OpenID message.
*/ */
function addExtension(&$extension_request) function addExtension($extension_request)
{ {
$extension_request->toMessage($this->message); $extension_request->toMessage($this->message);
} }
@ -2089,7 +2089,7 @@ class Auth_OpenID_SuccessResponse extends Auth_OpenID_ConsumerResponse {
foreach ($msg_args as $key => $value) { foreach ($msg_args as $key => $value) {
if (!$this->isSigned($ns_uri, $key)) { if (!$this->isSigned($ns_uri, $key)) {
return null; unset($msg_args[$key]);
} }
} }
@ -2167,7 +2167,7 @@ class Auth_OpenID_ServerErrorContainer {
/** /**
* @access private * @access private
*/ */
function fromMessage($message) static function fromMessage($message)
{ {
$error_text = $message->getArg( $error_text = $message->getArg(
Auth_OpenID_OPENID_NS, 'error', '<no error message supplied>'); Auth_OpenID_OPENID_NS, 'error', '<no error message supplied>');
@ -2227,4 +2227,4 @@ class Auth_OpenID_SetupNeededResponse extends Auth_OpenID_ConsumerResponse {
} }
} }
?>

View File

@ -37,7 +37,7 @@ class Auth_OpenID_CryptUtil {
* @param int $num_bytes The length of the return value * @param int $num_bytes The length of the return value
* @return string $bytes random bytes * @return string $bytes random bytes
*/ */
function getBytes($num_bytes) static function getBytes($num_bytes)
{ {
static $f = null; static $f = null;
$bytes = ''; $bytes = '';
@ -77,7 +77,7 @@ class Auth_OpenID_CryptUtil {
* @return string $result A string of randomly-chosen characters * @return string $result A string of randomly-chosen characters
* from $chrs * from $chrs
*/ */
function randomString($length, $population = null) static function randomString($length, $population = null)
{ {
if ($population === null) { if ($population === null) {
return Auth_OpenID_CryptUtil::getBytes($length); return Auth_OpenID_CryptUtil::getBytes($length);
@ -106,4 +106,3 @@ class Auth_OpenID_CryptUtil {
} }
} }
?>

View File

@ -128,4 +128,3 @@ class Auth_OpenID_DatabaseConnection {
} }
} }
?>

View File

@ -51,9 +51,9 @@ class Auth_OpenID_DiffieHellman {
$private = null, $lib = null) $private = null, $lib = null)
{ {
if ($lib === null) { if ($lib === null) {
$this->lib =& Auth_OpenID_getMathLib(); $this->lib = Auth_OpenID_getMathLib();
} else { } else {
$this->lib =& $lib; $this->lib = $lib;
} }
if ($mod === null) { if ($mod === null) {
@ -110,4 +110,4 @@ class Auth_OpenID_DiffieHellman {
} }
} }
?>

View File

@ -28,8 +28,34 @@ function Auth_OpenID_getOpenIDTypeURIs()
Auth_OpenID_TYPE_2_0, Auth_OpenID_TYPE_2_0,
Auth_OpenID_TYPE_1_2, Auth_OpenID_TYPE_1_2,
Auth_OpenID_TYPE_1_1, Auth_OpenID_TYPE_1_1,
Auth_OpenID_TYPE_1_0, Auth_OpenID_TYPE_1_0);
Auth_OpenID_RP_RETURN_TO_URL_TYPE); }
function Auth_OpenID_getOpenIDConsumerTypeURIs()
{
return array(Auth_OpenID_RP_RETURN_TO_URL_TYPE);
}
/*
* Provides a user-readable interpretation of a type uri.
* Useful for error messages.
*/
function Auth_OpenID_getOpenIDTypeName($type_uri) {
switch ($type_uri) {
case Auth_OpenID_TYPE_2_0_IDP:
return 'OpenID 2.0 IDP';
case Auth_OpenID_TYPE_2_0:
return 'OpenID 2.0';
case Auth_OpenID_TYPE_1_2:
return 'OpenID 1.2';
case Auth_OpenID_TYPE_1_1:
return 'OpenID 1.1';
case Auth_OpenID_TYPE_1_0:
return 'OpenID 1.0';
case Auth_OpenID_RP_RETURN_TO_URL_TYPE:
return 'OpenID relying party';
}
} }
/** /**
@ -124,7 +150,7 @@ class Auth_OpenID_ServiceEndpoint {
return in_array(Auth_OpenID_TYPE_2_0_IDP, $this->type_uris); return in_array(Auth_OpenID_TYPE_2_0_IDP, $this->type_uris);
} }
function fromOPEndpointURL($op_endpoint_url) static function fromOPEndpointURL($op_endpoint_url)
{ {
// Construct an OP-Identifier OpenIDServiceEndpoint object for // Construct an OP-Identifier OpenIDServiceEndpoint object for
// a given OP Endpoint URL // a given OP Endpoint URL
@ -171,15 +197,34 @@ class Auth_OpenID_ServiceEndpoint {
} }
} }
/*
* Parse the given document as XRDS looking for OpenID consumer services.
*
* @return array of Auth_OpenID_ServiceEndpoint or null if the
* document cannot be parsed.
*/
function consumerFromXRDS($uri, $xrds_text)
{
$xrds =& Auth_Yadis_XRDS::parseXRDS($xrds_text);
if ($xrds) {
$yadis_services =
$xrds->services(array('filter_MatchesAnyOpenIDConsumerType'));
return Auth_OpenID_makeOpenIDEndpoints($uri, $yadis_services);
}
return null;
}
/* /*
* Parse the given document as XRDS looking for OpenID services. * Parse the given document as XRDS looking for OpenID services.
* *
* @return array of Auth_OpenID_ServiceEndpoint or null if the * @return array of Auth_OpenID_ServiceEndpoint or null if the
* document cannot be parsed. * document cannot be parsed.
*/ */
function fromXRDS($uri, $xrds_text) static function fromXRDS($uri, $xrds_text)
{ {
$xrds =& Auth_Yadis_XRDS::parseXRDS($xrds_text); $xrds = Auth_Yadis_XRDS::parseXRDS($xrds_text);
if ($xrds) { if ($xrds) {
$yadis_services = $yadis_services =
@ -197,7 +242,7 @@ class Auth_OpenID_ServiceEndpoint {
* @return array of Auth_OpenID_ServiceEndpoint or null if * @return array of Auth_OpenID_ServiceEndpoint or null if
* endpoints cannot be created. * endpoints cannot be created.
*/ */
function fromDiscoveryResult($discoveryResult) static function fromDiscoveryResult($discoveryResult)
{ {
if ($discoveryResult->isXRDS()) { if ($discoveryResult->isXRDS()) {
return Auth_OpenID_ServiceEndpoint::fromXRDS( return Auth_OpenID_ServiceEndpoint::fromXRDS(
@ -210,7 +255,7 @@ class Auth_OpenID_ServiceEndpoint {
} }
} }
function fromHTML($uri, $html) static function fromHTML($uri, $html)
{ {
$discovery_types = array( $discovery_types = array(
array(Auth_OpenID_TYPE_2_0, array(Auth_OpenID_TYPE_2_0,
@ -273,7 +318,7 @@ function Auth_OpenID_findOPLocalIdentifier($service, $type_uris)
$service->parser->registerNamespace('xrd', $service->parser->registerNamespace('xrd',
Auth_Yadis_XMLNS_XRD_2_0); Auth_Yadis_XMLNS_XRD_2_0);
$parser =& $service->parser; $parser = $service->parser;
$permitted_tags = array(); $permitted_tags = array();
@ -305,7 +350,7 @@ function Auth_OpenID_findOPLocalIdentifier($service, $type_uris)
return $local_id; return $local_id;
} }
function filter_MatchesAnyOpenIDType(&$service) function filter_MatchesAnyOpenIDType($service)
{ {
$uris = $service->getTypes(); $uris = $service->getTypes();
@ -318,6 +363,19 @@ function filter_MatchesAnyOpenIDType(&$service)
return false; return false;
} }
function filter_MatchesAnyOpenIDConsumerType(&$service)
{
$uris = $service->getTypes();
foreach ($uris as $uri) {
if (in_array($uri, Auth_OpenID_getOpenIDConsumerTypeURIs())) {
return true;
}
}
return false;
}
function Auth_OpenID_bestMatchingService($service, $preferred_types) function Auth_OpenID_bestMatchingService($service, $preferred_types)
{ {
// Return the index of the first matching type, or something // Return the index of the first matching type, or something
@ -415,7 +473,7 @@ function Auth_OpenID_makeOpenIDEndpoints($uri, $yadis_services)
return $s; return $s;
} }
function Auth_OpenID_discoverWithYadis($uri, &$fetcher, function Auth_OpenID_discoverWithYadis($uri, $fetcher,
$endpoint_filter='Auth_OpenID_getOPOrUserServices', $endpoint_filter='Auth_OpenID_getOPOrUserServices',
$discover_function=null) $discover_function=null)
{ {
@ -433,12 +491,12 @@ function Auth_OpenID_discoverWithYadis($uri, &$fetcher,
$openid_services = array(); $openid_services = array();
$response = call_user_func_array($discover_function, $response = call_user_func_array($discover_function,
array($uri, &$fetcher)); array($uri, $fetcher));
$yadis_url = $response->normalized_uri; $yadis_url = $response->normalized_uri;
$yadis_services = array(); $yadis_services = array();
if ($response->isFailure()) { if ($response->isFailure() && !$response->isXRDS()) {
return array($uri, array()); return array($uri, array());
} }
@ -460,18 +518,18 @@ function Auth_OpenID_discoverWithYadis($uri, &$fetcher,
} }
$openid_services = call_user_func_array($endpoint_filter, $openid_services = call_user_func_array($endpoint_filter,
array(&$openid_services)); array($openid_services));
return array($yadis_url, $openid_services); return array($yadis_url, $openid_services);
} }
function Auth_OpenID_discoverURI($uri, &$fetcher) function Auth_OpenID_discoverURI($uri, $fetcher)
{ {
$uri = Auth_OpenID::normalizeUrl($uri); $uri = Auth_OpenID::normalizeUrl($uri);
return Auth_OpenID_discoverWithYadis($uri, $fetcher); return Auth_OpenID_discoverWithYadis($uri, $fetcher);
} }
function Auth_OpenID_discoverWithoutYadis($uri, &$fetcher) function Auth_OpenID_discoverWithoutYadis($uri, $fetcher)
{ {
$http_resp = @$fetcher->get($uri); $http_resp = @$fetcher->get($uri);
@ -490,7 +548,7 @@ function Auth_OpenID_discoverWithoutYadis($uri, &$fetcher)
return array($identity_url, $openid_services); return array($identity_url, $openid_services);
} }
function Auth_OpenID_discoverXRI($iname, &$fetcher) function Auth_OpenID_discoverXRI($iname, $fetcher)
{ {
$resolver = new Auth_Yadis_ProxyResolver($fetcher); $resolver = new Auth_Yadis_ProxyResolver($fetcher);
list($canonicalID, $yadis_services) = list($canonicalID, $yadis_services) =
@ -513,7 +571,7 @@ function Auth_OpenID_discoverXRI($iname, &$fetcher)
return array($iname, $openid_services); return array($iname, $openid_services);
} }
function Auth_OpenID_discover($uri, &$fetcher) function Auth_OpenID_discover($uri, $fetcher)
{ {
// If the fetcher (i.e., PHP) doesn't support SSL, we can't do // If the fetcher (i.e., PHP) doesn't support SSL, we can't do
// discovery on an HTTPS URL. // discovery on an HTTPS URL.
@ -545,4 +603,4 @@ function Auth_OpenID_discover($uri, &$fetcher)
return $result; return $result;
} }
?>

View File

@ -97,4 +97,3 @@ class Auth_OpenID_DumbStore extends Auth_OpenID_OpenIDStore {
} }
} }
?>

View File

@ -39,7 +39,7 @@ class Auth_OpenID_Extension {
* *
* Returns the message with the extension arguments added. * Returns the message with the extension arguments added.
*/ */
function toMessage(&$message) function toMessage($message)
{ {
$implicit = $message->isOpenID1(); $implicit = $message->isOpenID1();
$added = $message->namespaces->addAlias($this->ns_uri, $added = $message->namespaces->addAlias($this->ns_uri,
@ -59,4 +59,3 @@ class Auth_OpenID_Extension {
} }
} }
?>

View File

@ -367,7 +367,7 @@ class Auth_OpenID_FileStore extends Auth_OpenID_OpenIDStore {
} }
if ( abs($timestamp - time()) > $Auth_OpenID_SKEW ) { if ( abs($timestamp - time()) > $Auth_OpenID_SKEW ) {
return False; return false;
} }
if ($server_url) { if ($server_url) {
@ -519,7 +519,7 @@ class Auth_OpenID_FileStore extends Auth_OpenID_OpenIDStore {
/** /**
* @access private * @access private
*/ */
function _mkdtemp($dir) static function _mkdtemp($dir)
{ {
foreach (range(0, 4) as $i) { foreach (range(0, 4) as $i) {
$name = $dir . strval(DIRECTORY_SEPARATOR) . strval(getmypid()) . $name = $dir . strval(DIRECTORY_SEPARATOR) . strval(getmypid()) .
@ -615,4 +615,4 @@ class Auth_OpenID_FileStore extends Auth_OpenID_OpenIDStore {
} }
} }
?>

View File

@ -96,4 +96,3 @@ if (function_exists('hash_hmac') &&
define('Auth_OpenID_HMACSHA256_SUPPORTED', false); define('Auth_OpenID_HMACSHA256_SUPPORTED', false);
} }
?>

View File

@ -194,4 +194,3 @@ class Auth_OpenID_OpenIDStore {
} }
} }
?>

View File

@ -26,7 +26,7 @@ class Auth_OpenID_KVForm {
* @static * @static
* @access private * @access private
*/ */
function toArray($kvs, $strict=false) static function toArray($kvs, $strict=false)
{ {
$lines = explode("\n", $kvs); $lines = explode("\n", $kvs);
@ -78,7 +78,7 @@ class Auth_OpenID_KVForm {
* @static * @static
* @access private * @access private
*/ */
function fromArray($values) static function fromArray($values)
{ {
if ($values === null) { if ($values === null) {
return null; return null;
@ -109,4 +109,3 @@ class Auth_OpenID_KVForm {
} }
} }
?>

View File

@ -205,4 +205,3 @@ class Auth_OpenID_MemcachedStore extends Auth_OpenID_OpenIDStore {
} }
} }
?>

View File

@ -143,7 +143,7 @@ class Auth_OpenID_Mapping {
* Returns true if $thing is an Auth_OpenID_Mapping object; false * Returns true if $thing is an Auth_OpenID_Mapping object; false
* if not. * if not.
*/ */
function isA($thing) static function isA($thing)
{ {
return (is_object($thing) && return (is_object($thing) &&
strtolower(get_class($thing)) == 'auth_openid_mapping'); strtolower(get_class($thing)) == 'auth_openid_mapping');
@ -442,7 +442,7 @@ class Auth_OpenID_Message {
return $this->getOpenIDNamespace() == Auth_OpenID_OPENID2_NS; return $this->getOpenIDNamespace() == Auth_OpenID_OPENID2_NS;
} }
function fromPostArgs($args) static function fromPostArgs($args)
{ {
// Construct a Message containing a set of POST arguments // Construct a Message containing a set of POST arguments
$obj = new Auth_OpenID_Message(); $obj = new Auth_OpenID_Message();
@ -477,7 +477,7 @@ class Auth_OpenID_Message {
} }
} }
function fromOpenIDArgs($openid_args) static function fromOpenIDArgs($openid_args)
{ {
// Takes an array. // Takes an array.
@ -594,7 +594,7 @@ class Auth_OpenID_Message {
return $this->_openid_ns_uri; return $this->_openid_ns_uri;
} }
function fromKVForm($kvform_string) static function fromKVForm($kvform_string)
{ {
// Create a Message from a KVForm string // Create a Message from a KVForm string
return Auth_OpenID_Message::fromOpenIDArgs( return Auth_OpenID_Message::fromOpenIDArgs(
@ -917,4 +917,4 @@ class Auth_OpenID_Message {
} }
} }
?>

View File

@ -75,4 +75,3 @@ class Auth_OpenID_MySQLStore extends Auth_OpenID_SQLStore {
} }
} }
?>

View File

@ -106,4 +106,3 @@ function Auth_OpenID_mkNonce($when = null)
return $time_str . $salt; return $time_str . $salt;
} }
?>

View File

@ -21,7 +21,7 @@ define('PAPE_AUTH_PHISHING_RESISTANT',
'http://schemas.openid.net/pape/policies/2007/06/phishing-resistant'); 'http://schemas.openid.net/pape/policies/2007/06/phishing-resistant');
define('PAPE_TIME_VALIDATOR', define('PAPE_TIME_VALIDATOR',
'^[0-9]{4,4}-[0-9][0-9]-[0-9][0-9]T[0-9][0-9]:[0-9][0-9]:[0-9][0-9]Z$'); '/^[0-9]{4,4}-[0-9][0-9]-[0-9][0-9]T[0-9][0-9]:[0-9][0-9]:[0-9][0-9]Z$/');
/** /**
* A Provider Authentication Policy request, sent from a relying party * A Provider Authentication Policy request, sent from a relying party
* to a provider * to a provider
@ -82,7 +82,7 @@ class Auth_OpenID_PAPE_Request extends Auth_OpenID_Extension {
* Instantiate a Request object from the arguments in a checkid_* * Instantiate a Request object from the arguments in a checkid_*
* OpenID message * OpenID message
*/ */
function fromOpenIDRequest($request) static function fromOpenIDRequest($request)
{ {
$obj = new Auth_OpenID_PAPE_Request(); $obj = new Auth_OpenID_PAPE_Request();
$args = $request->message->getArgs(Auth_OpenID_PAPE_NS_URI); $args = $request->message->getArgs(Auth_OpenID_PAPE_NS_URI);
@ -201,7 +201,7 @@ class Auth_OpenID_PAPE_Response extends Auth_OpenID_Extension {
* @returns: A provider authentication policy response from the * @returns: A provider authentication policy response from the
* data that was supplied with the id_res response. * data that was supplied with the id_res response.
*/ */
function fromSuccessResponse($success_response) static function fromSuccessResponse($success_response)
{ {
$obj = new Auth_OpenID_PAPE_Response(); $obj = new Auth_OpenID_PAPE_Response();
@ -262,7 +262,7 @@ class Auth_OpenID_PAPE_Response extends Auth_OpenID_Extension {
$auth_time = Auth_OpenID::arrayGet($args, 'auth_time'); $auth_time = Auth_OpenID::arrayGet($args, 'auth_time');
if ($auth_time !== null) { if ($auth_time !== null) {
if (ereg(PAPE_TIME_VALIDATOR, $auth_time)) { if (preg_match(PAPE_TIME_VALIDATOR, $auth_time)) {
$this->auth_time = $auth_time; $this->auth_time = $auth_time;
} else if ($strict) { } else if ($strict) {
return false; return false;
@ -287,7 +287,7 @@ class Auth_OpenID_PAPE_Response extends Auth_OpenID_Extension {
} }
if ($this->auth_time !== null) { if ($this->auth_time !== null) {
if (!ereg(PAPE_TIME_VALIDATOR, $this->auth_time)) { if (!preg_match(PAPE_TIME_VALIDATOR, $this->auth_time)) {
return false; return false;
} }
@ -298,4 +298,3 @@ class Auth_OpenID_PAPE_Response extends Auth_OpenID_Extension {
} }
} }
?>

View File

@ -101,7 +101,7 @@ class Auth_OpenID_Parse {
* Starts with the tag name at a word boundary, where the tag name * Starts with the tag name at a word boundary, where the tag name
* is not a namespace * is not a namespace
*/ */
var $_tag_expr = "<%s\b(?!:)([^>]*?)(?:\/>|>(.*?)(?:<\/?%s\s*>|\Z))"; var $_tag_expr = "<%s\b(?!:)([^>]*?)(?:\/>|>(.*)(?:<\/?%s\s*>|\Z))";
var $_attr_find = '\b(\w+)=("[^"]*"|\'[^\']*\'|[^\'"\s\/<>]+)'; var $_attr_find = '\b(\w+)=("[^"]*"|\'[^\']*\'|[^\'"\s\/<>]+)';
@ -216,10 +216,30 @@ class Auth_OpenID_Parse {
} }
} }
function match($regexp, $text, &$match)
{
if (!is_callable('mb_ereg_search_init')) {
return preg_match($regexp, $text, $match);
}
$regexp = substr($regexp, 1, strlen($regexp) - 2 - strlen($this->_re_flags));
mb_ereg_search_init($text);
if (!mb_ereg_search($regexp)) {
return false;
}
list($match) = mb_ereg_search_getregs();
return true;
}
/** /**
* Find all link tags in a string representing a HTML document and * Find all link tags in a string representing a HTML document and
* return a list of their attributes. * return a list of their attributes.
* *
* @todo This is quite ineffective and may fail with the default
* pcre.backtrack_limit of 100000 in PHP 5.2, if $html is big.
* It should rather use stripos (in PHP5) or strpos()+strtoupper()
* in PHP4 to manage this.
*
* @param string $html The text to parse * @param string $html The text to parse
* @return array $list An array of arrays of attributes, one for each * @return array $list An array of arrays of attributes, one for each
* link tag * link tag
@ -244,18 +264,23 @@ class Auth_OpenID_Parse {
$stripped = substr($stripped, $html_begin, $stripped = substr($stripped, $html_begin,
$html_end - $html_begin); $html_end - $html_begin);
// Workaround to prevent PREG_BACKTRACK_LIMIT_ERROR:
$old_btlimit = ini_set( 'pcre.backtrack_limit', -1 );
// Try to find the <HEAD> tag. // Try to find the <HEAD> tag.
$head_re = $this->headFind(); $head_re = $this->headFind();
$head_matches = array(); $head_match = '';
if (!preg_match($head_re, $stripped, $head_matches)) { if (!$this->match($head_re, $stripped, $head_match)) {
return array(); ini_set( 'pcre.backtrack_limit', $old_btlimit );
return array();
} }
$link_data = array(); $link_data = array();
$link_matches = array(); $link_matches = array();
if (!preg_match_all($this->_link_find, $head_matches[0], if (!preg_match_all($this->_link_find, $head_match,
$link_matches)) { $link_matches)) {
ini_set( 'pcre.backtrack_limit', $old_btlimit );
return array(); return array();
} }
@ -273,6 +298,7 @@ class Auth_OpenID_Parse {
$link_data[] = $link_attrs; $link_data[] = $link_attrs;
} }
ini_set( 'pcre.backtrack_limit', $old_btlimit );
return $link_data; return $link_data;
} }
@ -349,4 +375,3 @@ function Auth_OpenID_legacy_discover($html_text, $server_rel,
} }
} }
?>

View File

@ -110,4 +110,3 @@ class Auth_OpenID_PostgreSQLStore extends Auth_OpenID_SQLStore {
} }
} }
?>

View File

@ -13,16 +13,6 @@
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache * @license http://www.apache.org/licenses/LICENSE-2.0 Apache
*/ */
/**
* Require the PEAR DB module because we'll need it for the SQL-based
* stores implemented here. We silence any errors from the inclusion
* because it might not be present, and a user of the SQL stores may
* supply an Auth_OpenID_DatabaseConnection instance that implements
* its own storage.
*/
global $__Auth_OpenID_PEAR_AVAILABLE;
$__Auth_OpenID_PEAR_AVAILABLE = @include_once 'DB.php';
/** /**
* @access private * @access private
*/ */
@ -89,8 +79,6 @@ class Auth_OpenID_SQLStore extends Auth_OpenID_OpenIDStore {
$associations_table = null, $associations_table = null,
$nonces_table = null) $nonces_table = null)
{ {
global $__Auth_OpenID_PEAR_AVAILABLE;
$this->associations_table_name = "oid_associations"; $this->associations_table_name = "oid_associations";
$this->nonces_table_name = "oid_nonces"; $this->nonces_table_name = "oid_nonces";
@ -113,7 +101,7 @@ class Auth_OpenID_SQLStore extends Auth_OpenID_OpenIDStore {
// constant, so only try to use it if PEAR is present. Note // constant, so only try to use it if PEAR is present. Note
// that Auth_Openid_Databaseconnection instances need not // that Auth_Openid_Databaseconnection instances need not
// implement ::setFetchMode for this reason. // implement ::setFetchMode for this reason.
if ($__Auth_OpenID_PEAR_AVAILABLE) { if (is_subclass_of($this->connection, 'db_common')) {
$this->connection->setFetchMode(DB_FETCHMODE_ASSOC); $this->connection->setFetchMode(DB_FETCHMODE_ASSOC);
} }
@ -482,7 +470,7 @@ class Auth_OpenID_SQLStore extends Auth_OpenID_OpenIDStore {
global $Auth_OpenID_SKEW; global $Auth_OpenID_SKEW;
if ( abs($timestamp - time()) > $Auth_OpenID_SKEW ) { if ( abs($timestamp - time()) > $Auth_OpenID_SKEW ) {
return False; return false;
} }
return $this->_add_nonce($server_url, $timestamp, $salt); return $this->_add_nonce($server_url, $timestamp, $salt);
@ -566,4 +554,4 @@ class Auth_OpenID_SQLStore extends Auth_OpenID_OpenIDStore {
} }
} }
?>

View File

@ -68,4 +68,3 @@ class Auth_OpenID_SQLiteStore extends Auth_OpenID_SQLStore {
} }
} }
?>

View File

@ -94,7 +94,7 @@ Auth_OpenID_registerNamespaceAlias(Auth_OpenID_SREG_NS_URI_1_1, 'sreg');
* $endpoint: The endpoint object as returned by OpenID discovery. * $endpoint: The endpoint object as returned by OpenID discovery.
* returns whether an sreg type was advertised by the endpoint * returns whether an sreg type was advertised by the endpoint
*/ */
function Auth_OpenID_supportsSReg(&$endpoint) function Auth_OpenID_supportsSReg($endpoint)
{ {
return ($endpoint->usesExtension(Auth_OpenID_SREG_NS_URI_1_1) || return ($endpoint->usesExtension(Auth_OpenID_SREG_NS_URI_1_1) ||
$endpoint->usesExtension(Auth_OpenID_SREG_NS_URI_1_0)); $endpoint->usesExtension(Auth_OpenID_SREG_NS_URI_1_0));
@ -122,7 +122,7 @@ class Auth_OpenID_SRegBase extends Auth_OpenID_Extension {
* *
* @access private * @access private
*/ */
function _getSRegNS(&$message) static function _getSRegNS($message)
{ {
$alias = null; $alias = null;
$found_ns_uri = null; $found_ns_uri = null;
@ -173,7 +173,7 @@ class Auth_OpenID_SRegRequest extends Auth_OpenID_SRegBase {
/** /**
* Initialize an empty simple registration request. * Initialize an empty simple registration request.
*/ */
function build($required=null, $optional=null, static function build($required=null, $optional=null,
$policy_url=null, $policy_url=null,
$sreg_ns_uri=Auth_OpenID_SREG_NS_URI, $sreg_ns_uri=Auth_OpenID_SREG_NS_URI,
$cls='Auth_OpenID_SRegRequest') $cls='Auth_OpenID_SRegRequest')
@ -213,7 +213,7 @@ class Auth_OpenID_SRegRequest extends Auth_OpenID_SRegBase {
* *
* Returns the newly created simple registration request * Returns the newly created simple registration request
*/ */
function fromOpenIDRequest($request, $cls='Auth_OpenID_SRegRequest') static function fromOpenIDRequest($request, $cls='Auth_OpenID_SRegRequest')
{ {
$obj = call_user_func_array(array($cls, 'build'), $obj = call_user_func_array(array($cls, 'build'),
@ -442,7 +442,7 @@ class Auth_OpenID_SRegResponse extends Auth_OpenID_SRegBase {
* string (unicode) value. For instance, the nickname should be * string (unicode) value. For instance, the nickname should be
* stored under the key 'nickname'. * stored under the key 'nickname'.
*/ */
function extractResponse($request, $data) static function extractResponse($request, $data)
{ {
$obj = new Auth_OpenID_SRegResponse(); $obj = new Auth_OpenID_SRegResponse();
$obj->ns_uri = $request->ns_uri; $obj->ns_uri = $request->ns_uri;
@ -471,7 +471,7 @@ class Auth_OpenID_SRegResponse extends Auth_OpenID_SRegBase {
* Returns a simple registration response containing the data that * Returns a simple registration response containing the data that
* was supplied with the C{id_res} response. * was supplied with the C{id_res} response.
*/ */
function fromSuccessResponse(&$success_response, $signed_only=true) static function fromSuccessResponse($success_response, $signed_only=true)
{ {
global $Auth_OpenID_sreg_data_fields; global $Auth_OpenID_sreg_data_fields;
@ -518,4 +518,4 @@ class Auth_OpenID_SRegResponse extends Auth_OpenID_SRegBase {
} }
} }
?>

View File

@ -43,7 +43,7 @@
* consumers to add extensions to their requests. For example, with * consumers to add extensions to their requests. For example, with
* sites using the Simple Registration * sites using the Simple Registration
* Extension * Extension
* (http://www.openidenabled.com/openid/simple-registration-extension/), * (http://openid.net/specs/openid-simple-registration-extension-1_0.html),
* a user can agree to have their nickname and e-mail address sent to * a user can agree to have their nickname and e-mail address sent to
* a site when they sign up. * a site when they sign up.
* *
@ -365,7 +365,7 @@ class Auth_OpenID_CheckAuthRequest extends Auth_OpenID_Request {
$this->message = null; $this->message = null;
} }
function fromMessage($message, $server=null) static function fromMessage($message, $server=null)
{ {
$required_keys = array('assoc_handle', 'sig', 'signed'); $required_keys = array('assoc_handle', 'sig', 'signed');
@ -396,7 +396,7 @@ class Auth_OpenID_CheckAuthRequest extends Auth_OpenID_Request {
return $result; return $result;
} }
function answer(&$signatory) function answer($signatory)
{ {
$is_valid = $signatory->verify($this->assoc_handle, $this->signed); $is_valid = $signatory->verify($this->assoc_handle, $this->signed);
@ -436,7 +436,7 @@ class Auth_OpenID_PlainTextServerSession {
var $needs_math = false; var $needs_math = false;
var $allowed_assoc_types = array('HMAC-SHA1', 'HMAC-SHA256'); var $allowed_assoc_types = array('HMAC-SHA1', 'HMAC-SHA256');
function fromMessage($unused_request) static function fromMessage($unused_request)
{ {
return new Auth_OpenID_PlainTextServerSession(); return new Auth_OpenID_PlainTextServerSession();
} }
@ -469,7 +469,7 @@ class Auth_OpenID_DiffieHellmanSHA1ServerSession {
$this->consumer_pubkey = $consumer_pubkey; $this->consumer_pubkey = $consumer_pubkey;
} }
function getDH($message) static function getDH($message)
{ {
$dh_modulus = $message->getArg(Auth_OpenID_OPENID_NS, 'dh_modulus'); $dh_modulus = $message->getArg(Auth_OpenID_OPENID_NS, 'dh_modulus');
$dh_gen = $message->getArg(Auth_OpenID_OPENID_NS, 'dh_gen'); $dh_gen = $message->getArg(Auth_OpenID_OPENID_NS, 'dh_gen');
@ -489,7 +489,7 @@ class Auth_OpenID_DiffieHellmanSHA1ServerSession {
$missing); $missing);
} }
$lib =& Auth_OpenID_getMathLib(); $lib = Auth_OpenID_getMathLib();
if ($dh_modulus || $dh_gen) { if ($dh_modulus || $dh_gen) {
$dh_modulus = $lib->base64ToLong($dh_modulus); $dh_modulus = $lib->base64ToLong($dh_modulus);
@ -523,7 +523,7 @@ class Auth_OpenID_DiffieHellmanSHA1ServerSession {
return array($dh, $consumer_pubkey); return array($dh, $consumer_pubkey);
} }
function fromMessage($message) static function fromMessage($message)
{ {
$result = Auth_OpenID_DiffieHellmanSHA1ServerSession::getDH($message); $result = Auth_OpenID_DiffieHellmanSHA1ServerSession::getDH($message);
@ -538,7 +538,7 @@ class Auth_OpenID_DiffieHellmanSHA1ServerSession {
function answer($secret) function answer($secret)
{ {
$lib =& Auth_OpenID_getMathLib(); $lib = Auth_OpenID_getMathLib();
$mac_key = $this->dh->xorSecret($this->consumer_pubkey, $secret, $mac_key = $this->dh->xorSecret($this->consumer_pubkey, $secret,
$this->hash_func); $this->hash_func);
return array( return array(
@ -560,7 +560,7 @@ class Auth_OpenID_DiffieHellmanSHA256ServerSession
var $hash_func = 'Auth_OpenID_SHA256'; var $hash_func = 'Auth_OpenID_SHA256';
var $allowed_assoc_types = array('HMAC-SHA256'); var $allowed_assoc_types = array('HMAC-SHA256');
function fromMessage($message) static function fromMessage($message)
{ {
$result = Auth_OpenID_DiffieHellmanSHA1ServerSession::getDH($message); $result = Auth_OpenID_DiffieHellmanSHA1ServerSession::getDH($message);
@ -582,7 +582,7 @@ class Auth_OpenID_DiffieHellmanSHA256ServerSession
class Auth_OpenID_AssociateRequest extends Auth_OpenID_Request { class Auth_OpenID_AssociateRequest extends Auth_OpenID_Request {
var $mode = "associate"; var $mode = "associate";
function getSessionClasses() static function getSessionClasses()
{ {
return array( return array(
'no-encryption' => 'Auth_OpenID_PlainTextServerSession', 'no-encryption' => 'Auth_OpenID_PlainTextServerSession',
@ -590,14 +590,14 @@ class Auth_OpenID_AssociateRequest extends Auth_OpenID_Request {
'DH-SHA256' => 'Auth_OpenID_DiffieHellmanSHA256ServerSession'); 'DH-SHA256' => 'Auth_OpenID_DiffieHellmanSHA256ServerSession');
} }
function Auth_OpenID_AssociateRequest(&$session, $assoc_type) function Auth_OpenID_AssociateRequest($session, $assoc_type)
{ {
$this->session =& $session; $this->session = $session;
$this->namespace = Auth_OpenID_OPENID2_NS; $this->namespace = Auth_OpenID_OPENID2_NS;
$this->assoc_type = $assoc_type; $this->assoc_type = $assoc_type;
} }
function fromMessage($message, $server=null) static function fromMessage($message, $server=null)
{ {
if ($message->isOpenID1()) { if ($message->isOpenID1()) {
$session_type = $message->getArg(Auth_OpenID_OPENID_NS, $session_type = $message->getArg(Auth_OpenID_OPENID_NS,
@ -696,7 +696,7 @@ class Auth_OpenID_AssociateRequest extends Auth_OpenID_Request {
'session_type', 'session_type',
$preferred_session_type); $preferred_session_type);
} }
$response->code = AUTH_OPENID_HTTP_ERROR;
return $response; return $response;
} }
} }
@ -734,7 +734,7 @@ class Auth_OpenID_CheckIDRequest extends Auth_OpenID_Request {
*/ */
var $namespace; var $namespace;
function make(&$message, $identity, $return_to, $trust_root = null, static function make($message, $identity, $return_to, $trust_root = null,
$immediate = false, $assoc_handle = null, $server = null) $immediate = false, $assoc_handle = null, $server = null)
{ {
if ($server === null) { if ($server === null) {
@ -752,7 +752,7 @@ class Auth_OpenID_CheckIDRequest extends Auth_OpenID_Request {
$assoc_handle, $server); $assoc_handle, $server);
$r->namespace = $message->getOpenIDNamespace(); $r->namespace = $message->getOpenIDNamespace();
$r->message =& $message; $r->message = $message;
if (!$r->trustRootValid()) { if (!$r->trustRootValid()) {
return new Auth_OpenID_UntrustedReturnURL($message, return new Auth_OpenID_UntrustedReturnURL($message,
@ -778,7 +778,7 @@ class Auth_OpenID_CheckIDRequest extends Auth_OpenID_Request {
} }
$this->return_to = $return_to; $this->return_to = $return_to;
$this->trust_root = $trust_root; $this->trust_root = $trust_root;
$this->server =& $server; $this->server = $server;
if ($immediate) { if ($immediate) {
$this->immediate = true; $this->immediate = true;
@ -817,11 +817,12 @@ class Auth_OpenID_CheckIDRequest extends Auth_OpenID_Request {
*/ */
function returnToVerified() function returnToVerified()
{ {
$fetcher = Auth_Yadis_Yadis::getHTTPFetcher();
return call_user_func_array($this->verifyReturnTo, return call_user_func_array($this->verifyReturnTo,
array($this->trust_root, $this->return_to)); array($this->trust_root, $this->return_to, $fetcher));
} }
function fromMessage(&$message, $server) static function fromMessage($message, $server)
{ {
$mode = $message->getArg(Auth_OpenID_OPENID_NS, 'mode'); $mode = $message->getArg(Auth_OpenID_OPENID_NS, 'mode');
$immediate = null; $immediate = null;
@ -1097,7 +1098,7 @@ class Auth_OpenID_CheckIDRequest extends Auth_OpenID_Request {
in OpenID 1.x immediate mode.'); in OpenID 1.x immediate mode.');
} }
$setup_request =& new Auth_OpenID_CheckIDRequest( $setup_request = new Auth_OpenID_CheckIDRequest(
$this->identity, $this->identity,
$this->return_to, $this->return_to,
$this->trust_root, $this->trust_root,
@ -1183,9 +1184,9 @@ class Auth_OpenID_CheckIDRequest extends Auth_OpenID_Request {
*/ */
class Auth_OpenID_ServerResponse { class Auth_OpenID_ServerResponse {
function Auth_OpenID_ServerResponse(&$request) function Auth_OpenID_ServerResponse($request)
{ {
$this->request =& $request; $this->request = $request;
$this->fields = new Auth_OpenID_Message($this->request->namespace); $this->fields = new Auth_OpenID_Message($this->request->namespace);
} }
@ -1310,10 +1311,10 @@ class Auth_OpenID_Signatory {
/** /**
* Create a new signatory using a given store. * Create a new signatory using a given store.
*/ */
function Auth_OpenID_Signatory(&$store) function Auth_OpenID_Signatory($store)
{ {
// assert store is not None // assert store is not None
$this->store =& $store; $this->store = $store;
} }
/** /**
@ -1447,7 +1448,7 @@ class Auth_OpenID_Encoder {
* Encode an {@link Auth_OpenID_ServerResponse} and return an * Encode an {@link Auth_OpenID_ServerResponse} and return an
* {@link Auth_OpenID_WebResponse}. * {@link Auth_OpenID_WebResponse}.
*/ */
function encode(&$response) function encode($response)
{ {
$cls = $this->responseFactory; $cls = $this->responseFactory;
@ -1463,10 +1464,14 @@ class Auth_OpenID_Encoder {
array('location' => $location)); array('location' => $location));
} else if ($encode_as == Auth_OpenID_ENCODE_HTML_FORM) { } else if ($encode_as == Auth_OpenID_ENCODE_HTML_FORM) {
$wr = new $cls(AUTH_OPENID_HTTP_OK, array(), $wr = new $cls(AUTH_OPENID_HTTP_OK, array(),
$response->toFormMarkup()); $response->toHTML());
} else { } else {
return new Auth_OpenID_EncodingError($response); return new Auth_OpenID_EncodingError($response);
} }
/* Allow the response to carry a custom error code (ex: for Association errors) */
if(isset($response->code)) {
$wr->code = $response->code;
}
return $wr; return $wr;
} }
} }
@ -1478,16 +1483,16 @@ class Auth_OpenID_Encoder {
*/ */
class Auth_OpenID_SigningEncoder extends Auth_OpenID_Encoder { class Auth_OpenID_SigningEncoder extends Auth_OpenID_Encoder {
function Auth_OpenID_SigningEncoder(&$signatory) function Auth_OpenID_SigningEncoder($signatory)
{ {
$this->signatory =& $signatory; $this->signatory = $signatory;
} }
/** /**
* Sign an {@link Auth_OpenID_ServerResponse} and return an * Sign an {@link Auth_OpenID_ServerResponse} and return an
* {@link Auth_OpenID_WebResponse}. * {@link Auth_OpenID_WebResponse}.
*/ */
function encode(&$response) function encode($response)
{ {
// the isinstance is a bit of a kludge... it means there isn't // the isinstance is a bit of a kludge... it means there isn't
// really an adapter to make the interfaces quite match. // really an adapter to make the interfaces quite match.
@ -1516,9 +1521,9 @@ class Auth_OpenID_SigningEncoder extends Auth_OpenID_Encoder {
*/ */
class Auth_OpenID_Decoder { class Auth_OpenID_Decoder {
function Auth_OpenID_Decoder(&$server) function Auth_OpenID_Decoder($server)
{ {
$this->server =& $server; $this->server = $server;
$this->handlers = array( $this->handlers = array(
'checkid_setup' => 'Auth_OpenID_CheckIDRequest', 'checkid_setup' => 'Auth_OpenID_CheckIDRequest',
@ -1599,9 +1604,9 @@ class Auth_OpenID_Decoder {
* @package OpenID * @package OpenID
*/ */
class Auth_OpenID_EncodingError { class Auth_OpenID_EncodingError {
function Auth_OpenID_EncodingError(&$response) function Auth_OpenID_EncodingError($response)
{ {
$this->response =& $response; $this->response = $response;
} }
} }
@ -1674,14 +1679,14 @@ class Auth_OpenID_UntrustedReturnURL extends Auth_OpenID_ServerError {
* @package OpenID * @package OpenID
*/ */
class Auth_OpenID_Server { class Auth_OpenID_Server {
function Auth_OpenID_Server(&$store, $op_endpoint=null) function Auth_OpenID_Server($store, $op_endpoint=null)
{ {
$this->store =& $store; $this->store = $store;
$this->signatory =& new Auth_OpenID_Signatory($this->store); $this->signatory = new Auth_OpenID_Signatory($this->store);
$this->encoder =& new Auth_OpenID_SigningEncoder($this->signatory); $this->encoder = new Auth_OpenID_SigningEncoder($this->signatory);
$this->decoder =& new Auth_OpenID_Decoder($this); $this->decoder = new Auth_OpenID_Decoder($this);
$this->op_endpoint = $op_endpoint; $this->op_endpoint = $op_endpoint;
$this->negotiator =& Auth_OpenID_getDefaultNegotiator(); $this->negotiator = Auth_OpenID_getDefaultNegotiator();
} }
/** /**
@ -1699,7 +1704,7 @@ class Auth_OpenID_Server {
{ {
if (method_exists($this, "openid_" . $request->mode)) { if (method_exists($this, "openid_" . $request->mode)) {
$handler = array($this, "openid_" . $request->mode); $handler = array($this, "openid_" . $request->mode);
return call_user_func($handler, $request); return call_user_func($handler, &$request);
} }
return null; return null;
} }
@ -1707,7 +1712,7 @@ class Auth_OpenID_Server {
/** /**
* The callback for 'check_authentication' messages. * The callback for 'check_authentication' messages.
*/ */
function openid_check_authentication(&$request) function openid_check_authentication($request)
{ {
return $request->answer($this->signatory); return $request->answer($this->signatory);
} }
@ -1715,7 +1720,7 @@ class Auth_OpenID_Server {
/** /**
* The callback for 'associate' messages. * The callback for 'associate' messages.
*/ */
function openid_associate(&$request) function openid_associate($request)
{ {
$assoc_type = $request->assoc_type; $assoc_type = $request->assoc_type;
$session_type = $request->session->session_type; $session_type = $request->session->session_type;
@ -1738,7 +1743,7 @@ class Auth_OpenID_Server {
* Encodes as response in the appropriate format suitable for * Encodes as response in the appropriate format suitable for
* sending to the user agent. * sending to the user agent.
*/ */
function encodeResponse(&$response) function encodeResponse($response)
{ {
return $this->encoder->encode($response); return $this->encoder->encode($response);
} }
@ -1757,4 +1762,4 @@ class Auth_OpenID_Server {
} }
} }
?>

View File

@ -34,4 +34,3 @@ class Auth_OpenID_ServerRequest {
} }
} }
?>

View File

@ -58,7 +58,7 @@ class Auth_OpenID_TrustRoot {
* @return The URL upon which relying party discovery should be * @return The URL upon which relying party discovery should be
* run in order to verify the return_to URL * run in order to verify the return_to URL
*/ */
function buildDiscoveryURL($realm) static function buildDiscoveryURL($realm)
{ {
$parsed = Auth_OpenID_TrustRoot::_parse($realm); $parsed = Auth_OpenID_TrustRoot::_parse($realm);
@ -93,7 +93,7 @@ class Auth_OpenID_TrustRoot {
* @return mixed $parsed Either an associative array of trust root * @return mixed $parsed Either an associative array of trust root
* parts or false if parsing failed. * parts or false if parsing failed.
*/ */
function _parse($trust_root) static function _parse($trust_root)
{ {
$trust_root = Auth_OpenID_urinorm($trust_root); $trust_root = Auth_OpenID_urinorm($trust_root);
if ($trust_root === null) { if ($trust_root === null) {
@ -199,7 +199,7 @@ class Auth_OpenID_TrustRoot {
* @param string $trust_root The trust root to check * @param string $trust_root The trust root to check
* @return bool $sanity Whether the trust root looks OK * @return bool $sanity Whether the trust root looks OK
*/ */
function isSane($trust_root) static function isSane($trust_root)
{ {
$parts = Auth_OpenID_TrustRoot::_parse($trust_root); $parts = Auth_OpenID_TrustRoot::_parse($trust_root);
if ($parts === false) { if ($parts === false) {
@ -269,7 +269,7 @@ class Auth_OpenID_TrustRoot {
* @return bool $matches Whether the URL matches against the * @return bool $matches Whether the URL matches against the
* trust root * trust root
*/ */
function match($trust_root, $url) static function match($trust_root, $url)
{ {
$trust_root_parsed = Auth_OpenID_TrustRoot::_parse($trust_root); $trust_root_parsed = Auth_OpenID_TrustRoot::_parse($trust_root);
$url_parsed = Auth_OpenID_TrustRoot::_parse($url); $url_parsed = Auth_OpenID_TrustRoot::_parse($url);
@ -341,7 +341,7 @@ class Auth_OpenID_TrustRoot {
* @returns: The endpoint URL or None if the endpoint is not a * @returns: The endpoint URL or None if the endpoint is not a
* relying party endpoint. * relying party endpoint.
*/ */
function filter_extractReturnURL(&$endpoint) function filter_extractReturnURL($endpoint)
{ {
if ($endpoint->matchTypes(array(Auth_OpenID_RP_RETURN_TO_URL_TYPE))) { if ($endpoint->matchTypes(array(Auth_OpenID_RP_RETURN_TO_URL_TYPE))) {
return $endpoint; return $endpoint;
@ -394,14 +394,14 @@ function Auth_OpenID_returnToMatches($allowed_return_to_urls, $return_to)
* Given a relying party discovery URL return a list of return_to * Given a relying party discovery URL return a list of return_to
* URLs. * URLs.
*/ */
function Auth_OpenID_getAllowedReturnURLs($relying_party_url, &$fetcher, function Auth_OpenID_getAllowedReturnURLs($relying_party_url, $fetcher,
$discover_function=null) $discover_function=null)
{ {
if ($discover_function === null) { if ($discover_function === null) {
$discover_function = array('Auth_Yadis_Yadis', 'discover'); $discover_function = array('Auth_Yadis_Yadis', 'discover');
} }
$xrds_parse_cb = array('Auth_OpenID_ServiceEndpoint', 'fromXRDS'); $xrds_parse_cb = array('Auth_OpenID_ServiceEndpoint', 'consumerFromXRDS');
list($rp_url_after_redirects, $endpoints) = list($rp_url_after_redirects, $endpoints) =
Auth_Yadis_getServiceEndpoints($relying_party_url, $xrds_parse_cb, Auth_Yadis_getServiceEndpoints($relying_party_url, $xrds_parse_cb,
@ -413,7 +413,7 @@ function Auth_OpenID_getAllowedReturnURLs($relying_party_url, &$fetcher,
} }
call_user_func_array($discover_function, call_user_func_array($discover_function,
array($relying_party_url, $fetcher)); array($relying_party_url, &$fetcher));
$return_to_urls = array(); $return_to_urls = array();
$matching_endpoints = Auth_OpenID_extractReturnURL($endpoints); $matching_endpoints = Auth_OpenID_extractReturnURL($endpoints);
@ -435,7 +435,7 @@ function Auth_OpenID_getAllowedReturnURLs($relying_party_url, &$fetcher,
* *
* @return true if the return_to URL is valid for the realm * @return true if the return_to URL is valid for the realm
*/ */
function Auth_OpenID_verifyReturnTo($realm_str, $return_to, &$fetcher, function Auth_OpenID_verifyReturnTo($realm_str, $return_to, $fetcher,
$_vrfy='Auth_OpenID_getAllowedReturnURLs') $_vrfy='Auth_OpenID_getAllowedReturnURLs')
{ {
$disco_url = Auth_OpenID_TrustRoot::buildDiscoveryURL($realm_str); $disco_url = Auth_OpenID_TrustRoot::buildDiscoveryURL($realm_str);
@ -445,7 +445,7 @@ function Auth_OpenID_verifyReturnTo($realm_str, $return_to, &$fetcher,
} }
$allowable_urls = call_user_func_array($_vrfy, $allowable_urls = call_user_func_array($_vrfy,
array($disco_url, &$fetcher)); array($disco_url, $fetcher));
// The realm_str could not be parsed. // The realm_str could not be parsed.
if ($allowable_urls === false) { if ($allowable_urls === false) {
@ -459,4 +459,3 @@ function Auth_OpenID_verifyReturnTo($realm_str, $return_to, &$fetcher,
} }
} }
?>

View File

@ -246,4 +246,4 @@ function Auth_OpenID_urinorm($uri)
return $scheme . '://' . $authority . $path . $query . $fragment; return $scheme . '://' . $authority . $path . $query . $fragment;
} }
?>

View File

@ -115,12 +115,40 @@ class Auth_Yadis_HTTPFetcher {
/** /**
* @access private * @access private
*/ */
function _findRedirect($headers) function _findRedirect($headers, $url)
{ {
foreach ($headers as $line) { foreach ($headers as $line) {
if (strpos(strtolower($line), "location: ") === 0) { if (strpos(strtolower($line), "location: ") === 0) {
$parts = explode(" ", $line, 2); $parts = explode(" ", $line, 2);
return $parts[1]; $loc = $parts[1];
$ppos = strpos($loc, "://");
if ($ppos === false || $ppos > strpos($loc, "/")) {
/* no host; add it */
$hpos = strpos($url, "://");
$prt = substr($url, 0, $hpos+3);
$url = substr($url, $hpos+3);
if (substr($loc, 0, 1) == "/") {
/* absolute path */
$fspos = strpos($url, "/");
if ($fspos) $loc = $prt.substr($url, 0, $fspos).$loc;
else $loc = $prt.$url.$loc;
} else {
/* relative path */
$pp = $prt;
while (1) {
$xpos = strpos($url, "/");
if ($xpos === false) break;
$apos = strpos($url, "?");
if ($apos !== false && $apos < $xpos) break;
$apos = strpos($url, "&");
if ($apos !== false && $apos < $xpos) break;
$pp .= substr($url, 0, $xpos+1);
$url = substr($url, $xpos+1);
}
$loc = $pp.$loc;
}
}
return $loc;
} }
} }
return null; return null;
@ -144,4 +172,3 @@ class Auth_Yadis_HTTPFetcher {
} }
} }
?>

View File

@ -387,11 +387,11 @@ class Auth_Yadis_Discovery {
* @param string $session_key_suffix The optional session key * @param string $session_key_suffix The optional session key
* suffix override. * suffix override.
*/ */
function Auth_Yadis_Discovery(&$session, $url, function Auth_Yadis_Discovery($session, $url,
$session_key_suffix = null) $session_key_suffix = null)
{ {
/// Initialize a discovery object /// Initialize a discovery object
$this->session =& $session; $this->session = $session;
$this->url = $url; $this->url = $url;
if ($session_key_suffix === null) { if ($session_key_suffix === null) {
$session_key_suffix = $this->DEFAULT_SUFFIX; $session_key_suffix = $this->DEFAULT_SUFFIX;
@ -405,7 +405,7 @@ class Auth_Yadis_Discovery {
* Return the next authentication service for the pair of * Return the next authentication service for the pair of
* user_input and session. This function handles fallback. * user_input and session. This function handles fallback.
*/ */
function getNextService($discover_cb, &$fetcher) function getNextService($discover_cb, $fetcher)
{ {
$manager = $this->getManager(); $manager = $this->getManager();
if (!$manager || (!$manager->services)) { if (!$manager || (!$manager->services)) {
@ -413,7 +413,7 @@ class Auth_Yadis_Discovery {
list($yadis_url, $services) = call_user_func($discover_cb, list($yadis_url, $services) = call_user_func($discover_cb,
$this->url, $this->url,
$fetcher); &$fetcher);
$manager = $this->createManager($services, $yadis_url); $manager = $this->createManager($services, $yadis_url);
} }
@ -466,7 +466,7 @@ class Auth_Yadis_Discovery {
* @param $force True if the manager should be returned regardless * @param $force True if the manager should be returned regardless
* of whether it's a manager for $this->url. * of whether it's a manager for $this->url.
*/ */
function &getManager($force=false) function getManager($force=false)
{ {
// Extract the YadisServiceManager for this object's URL and // Extract the YadisServiceManager for this object's URL and
// suffix from the session. // suffix from the session.
@ -481,16 +481,13 @@ class Auth_Yadis_Discovery {
if ($manager && ($manager->forURL($this->url) || $force)) { if ($manager && ($manager->forURL($this->url) || $force)) {
return $manager; return $manager;
} else {
$unused = null;
return $unused;
} }
} }
/** /**
* @access private * @access private
*/ */
function &createManager($services, $yadis_url = null) function createManager($services, $yadis_url = null)
{ {
$key = $this->getSessionKey(); $key = $this->getSessionKey();
if ($this->getManager()) { if ($this->getManager()) {
@ -504,10 +501,6 @@ class Auth_Yadis_Discovery {
$this->session->set($this->session_key, $this->session->set($this->session_key,
serialize($loader->toSession($manager))); serialize($loader->toSession($manager)));
return $manager; return $manager;
} else {
// Oh, PHP.
$unused = null;
return $unused;
} }
} }
@ -526,4 +519,3 @@ class Auth_Yadis_Discovery {
} }
} }
?>

View File

@ -56,4 +56,3 @@ function Auth_Yadis_startswith($s, $stuff)
return strpos($s, $stuff) === 0; return strpos($s, $stuff) === 0;
} }
?>

View File

@ -109,9 +109,9 @@ class Auth_Yadis_ParanoidHTTPFetcher extends Auth_Yadis_HTTPFetcher {
} }
curl_setopt($c, CURLOPT_WRITEFUNCTION, curl_setopt($c, CURLOPT_WRITEFUNCTION,
array(&$this, "_writeData")); array($this, "_writeData"));
curl_setopt($c, CURLOPT_HEADERFUNCTION, curl_setopt($c, CURLOPT_HEADERFUNCTION,
array(&$this, "_writeHeader")); array($this, "_writeHeader"));
if ($extra_headers) { if ($extra_headers) {
curl_setopt($c, CURLOPT_HTTPHEADER, $extra_headers); curl_setopt($c, CURLOPT_HTTPHEADER, $extra_headers);
@ -128,6 +128,10 @@ class Auth_Yadis_ParanoidHTTPFetcher extends Auth_Yadis_HTTPFetcher {
curl_setopt($c, CURLOPT_TIMEOUT, $off); curl_setopt($c, CURLOPT_TIMEOUT, $off);
curl_setopt($c, CURLOPT_URL, $url); curl_setopt($c, CURLOPT_URL, $url);
if (defined('Auth_OpenID_VERIFY_HOST')) {
curl_setopt($c, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($c, CURLOPT_SSL_VERIFYHOST, 2);
}
curl_exec($c); curl_exec($c);
$code = curl_getinfo($c, CURLINFO_HTTP_CODE); $code = curl_getinfo($c, CURLINFO_HTTP_CODE);
@ -142,12 +146,17 @@ class Auth_Yadis_ParanoidHTTPFetcher extends Auth_Yadis_HTTPFetcher {
} }
if (in_array($code, array(301, 302, 303, 307))) { if (in_array($code, array(301, 302, 303, 307))) {
$url = $this->_findRedirect($headers); $url = $this->_findRedirect($headers, $url);
$redir = true; $redir = true;
} else { } else {
$redir = false; $redir = false;
curl_close($c); curl_close($c);
if (defined('Auth_OpenID_VERIFY_HOST') &&
$this->isHTTPS($url)) {
Auth_OpenID::log('OpenID: Verified SSL host %s using '.
'curl/get', $url);
}
$new_headers = array(); $new_headers = array();
foreach ($headers as $header) { foreach ($headers as $header) {
@ -190,7 +199,12 @@ class Auth_Yadis_ParanoidHTTPFetcher extends Auth_Yadis_HTTPFetcher {
curl_setopt($c, CURLOPT_TIMEOUT, $this->timeout); curl_setopt($c, CURLOPT_TIMEOUT, $this->timeout);
curl_setopt($c, CURLOPT_URL, $url); curl_setopt($c, CURLOPT_URL, $url);
curl_setopt($c, CURLOPT_WRITEFUNCTION, curl_setopt($c, CURLOPT_WRITEFUNCTION,
array(&$this, "_writeData")); array($this, "_writeData"));
if (defined('Auth_OpenID_VERIFY_HOST')) {
curl_setopt($c, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($c, CURLOPT_SSL_VERIFYHOST, 2);
}
curl_exec($c); curl_exec($c);
@ -198,9 +212,15 @@ class Auth_Yadis_ParanoidHTTPFetcher extends Auth_Yadis_HTTPFetcher {
if (!$code) { if (!$code) {
Auth_OpenID::log("Got no response code when fetching %s", $url); Auth_OpenID::log("Got no response code when fetching %s", $url);
Auth_OpenID::log("CURL error (%s): %s",
curl_errno($c), curl_error($c));
return null; return null;
} }
if (defined('Auth_OpenID_VERIFY_HOST') && $this->isHTTPS($url)) {
Auth_OpenID::log('OpenID: Verified SSL host %s using '.
'curl/post', $url);
}
$body = $this->data; $body = $this->data;
curl_close($c); curl_close($c);
@ -223,4 +243,3 @@ class Auth_Yadis_ParanoidHTTPFetcher extends Auth_Yadis_HTTPFetcher {
} }
} }
?>

View File

@ -256,4 +256,3 @@ class Auth_Yadis_ParseHTML {
} }
} }
?>

View File

@ -122,7 +122,7 @@ class Auth_Yadis_PlainHTTPFetcher extends Auth_Yadis_HTTPFetcher {
$code = $http_code[1]; $code = $http_code[1];
if (in_array($code, array('301', '302'))) { if (in_array($code, array('301', '302'))) {
$url = $this->_findRedirect($headers); $url = $this->_findRedirect($headers, $url);
$redir = true; $redir = true;
} else { } else {
$redir = false; $redir = false;
@ -246,4 +246,3 @@ class Auth_Yadis_PlainHTTPFetcher extends Auth_Yadis_HTTPFetcher {
} }
} }
?>

View File

@ -310,20 +310,16 @@ $__Auth_Yadis_defaultParser = null;
* @param Auth_Yadis_XMLParser $parser An instance of a * @param Auth_Yadis_XMLParser $parser An instance of a
* Auth_Yadis_XMLParser subclass. * Auth_Yadis_XMLParser subclass.
*/ */
function Auth_Yadis_setDefaultParser(&$parser) function Auth_Yadis_setDefaultParser($parser)
{ {
global $__Auth_Yadis_defaultParser; global $__Auth_Yadis_defaultParser;
$__Auth_Yadis_defaultParser =& $parser; $__Auth_Yadis_defaultParser = $parser;
} }
function Auth_Yadis_getSupportedExtensions() function Auth_Yadis_getSupportedExtensions()
{ {
return array( return array('dom' => 'Auth_Yadis_dom',
'dom' => array('classname' => 'Auth_Yadis_dom', 'domxml' => 'Auth_Yadis_domxml');
'libname' => array('dom.so', 'dom.dll')),
'domxml' => array('classname' => 'Auth_Yadis_domxml',
'libname' => array('domxml.so', 'php_domxml.dll')),
);
} }
/** /**
@ -332,7 +328,7 @@ function Auth_Yadis_getSupportedExtensions()
* Auth_Yadis_setDefaultParser has been called, the parser used in * Auth_Yadis_setDefaultParser has been called, the parser used in
* that call will be returned instead. * that call will be returned instead.
*/ */
function &Auth_Yadis_getXMLParser() function Auth_Yadis_getXMLParser()
{ {
global $__Auth_Yadis_defaultParser; global $__Auth_Yadis_defaultParser;
@ -340,35 +336,17 @@ function &Auth_Yadis_getXMLParser()
return $__Auth_Yadis_defaultParser; return $__Auth_Yadis_defaultParser;
} }
$p = null; foreach(Auth_Yadis_getSupportedExtensions() as $extension => $classname)
$classname = null; {
if (extension_loaded($extension))
$extensions = Auth_Yadis_getSupportedExtensions(); {
$p = new $classname();
// Return a wrapper for the resident implementation, if any.
foreach ($extensions as $name => $params) {
if (!extension_loaded($name)) {
foreach ($params['libname'] as $libname) {
if (@dl($libname)) {
$classname = $params['classname'];
}
}
} else {
$classname = $params['classname'];
}
if (isset($classname)) {
$p = new $classname();
return $p;
}
}
if (!isset($p)) {
trigger_error('No XML parser was found', E_USER_ERROR);
} else {
Auth_Yadis_setDefaultParser($p); Auth_Yadis_setDefaultParser($p);
return $p;
}
} }
return $p; return false;
} }
?>

View File

@ -255,11 +255,11 @@ class Auth_Yadis_XRDS {
* Instantiate a Auth_Yadis_XRDS object. Requires an XPath * Instantiate a Auth_Yadis_XRDS object. Requires an XPath
* instance which has been used to parse a valid XRDS document. * instance which has been used to parse a valid XRDS document.
*/ */
function Auth_Yadis_XRDS(&$xmlParser, &$xrdNodes) function Auth_Yadis_XRDS($xmlParser, $xrdNodes)
{ {
$this->parser =& $xmlParser; $this->parser = $xmlParser;
$this->xrdNode = $xrdNodes[count($xrdNodes) - 1]; $this->xrdNode = $xrdNodes[count($xrdNodes) - 1];
$this->allXrdNodes =& $xrdNodes; $this->allXrdNodes = $xrdNodes;
$this->serviceList = array(); $this->serviceList = array();
$this->_parse(); $this->_parse();
} }
@ -273,7 +273,7 @@ class Auth_Yadis_XRDS {
* @return mixed $xrds An instance of Auth_Yadis_XRDS or null, * @return mixed $xrds An instance of Auth_Yadis_XRDS or null,
* depending on the validity of $xml_string * depending on the validity of $xml_string
*/ */
function &parseXRDS($xml_string, $extra_ns_map = null) static function parseXRDS($xml_string, $extra_ns_map = null)
{ {
$_null = null; $_null = null;
@ -352,9 +352,9 @@ class Auth_Yadis_XRDS {
$services = $this->parser->evalXPath('xrd:Service', $this->xrdNode); $services = $this->parser->evalXPath('xrd:Service', $this->xrdNode);
foreach ($services as $node) { foreach ($services as $node) {
$s =& new Auth_Yadis_Service(); $s = new Auth_Yadis_Service();
$s->element = $node; $s->element = $node;
$s->parser =& $this->parser; $s->parser = $this->parser;
$priority = $s->getPriority(); $priority = $s->getPriority();
@ -428,7 +428,8 @@ class Auth_Yadis_XRDS {
$matches = 0; $matches = 0;
foreach ($filters as $filter) { foreach ($filters as $filter) {
if (call_user_func_array($filter, array($service))) {
if (call_user_func_array($filter, array(&$service))) {
$matches++; $matches++;
if ($filter_mode == SERVICES_YADIS_MATCH_ANY) { if ($filter_mode == SERVICES_YADIS_MATCH_ANY) {
@ -475,4 +476,3 @@ class Auth_Yadis_XRDS {
} }
} }
?>

View File

@ -190,7 +190,7 @@ function Auth_Yadis_getCanonicalID($iname, $xrds)
// Now nodes are in reverse order. // Now nodes are in reverse order.
$xrd_list = array_reverse($xrds->allXrdNodes); $xrd_list = array_reverse($xrds->allXrdNodes);
$parser =& $xrds->parser; $parser = $xrds->parser;
$node = $xrd_list[0]; $node = $xrd_list[0];
$canonicalID_nodes = $parser->evalXPath('xrd:CanonicalID', $node); $canonicalID_nodes = $parser->evalXPath('xrd:CanonicalID', $node);
@ -231,4 +231,4 @@ function Auth_Yadis_getCanonicalID($iname, $xrds)
return $canonicalID; return $canonicalID;
} }
?>

View File

@ -8,9 +8,9 @@ require_once 'Auth/Yadis/XRDS.php';
require_once 'Auth/Yadis/XRI.php'; require_once 'Auth/Yadis/XRI.php';
class Auth_Yadis_ProxyResolver { class Auth_Yadis_ProxyResolver {
function Auth_Yadis_ProxyResolver(&$fetcher, $proxy_url = null) function Auth_Yadis_ProxyResolver($fetcher, $proxy_url = null)
{ {
$this->fetcher =& $fetcher; $this->fetcher = $fetcher;
$this->proxy_url = $proxy_url; $this->proxy_url = $proxy_url;
if (!$this->proxy_url) { if (!$this->proxy_url) {
$this->proxy_url = Auth_Yadis_getDefaultProxy(); $this->proxy_url = Auth_Yadis_getDefaultProxy();
@ -69,4 +69,4 @@ class Auth_Yadis_ProxyResolver {
} }
} }
?>

View File

@ -105,7 +105,7 @@ class Auth_Yadis_DiscoveryResult {
function usedYadisLocation() function usedYadisLocation()
{ {
// Was the Yadis protocol's indirection used? // Was the Yadis protocol's indirection used?
return $this->normalized_uri != $this->xrds_uri; return ($this->xrds_uri && $this->normalized_uri != $this->xrds_uri);
} }
function isXRDS() function isXRDS()
@ -141,7 +141,7 @@ function Auth_Yadis_getServiceEndpoints($input_url, $xrds_parse_func,
} }
$yadis_result = call_user_func_array($discover_func, $yadis_result = call_user_func_array($discover_func,
array($input_url, $fetcher)); array($input_url, &$fetcher));
if ($yadis_result === null) { if ($yadis_result === null) {
return array($input_url, array()); return array($input_url, array());
@ -196,7 +196,7 @@ function Auth_Yadis_getServiceEndpoints($input_url, $xrds_parse_func,
* The filter functions (whose names appear in the array passed to * The filter functions (whose names appear in the array passed to
* services()) take the following form: * services()) take the following form:
* *
* <pre> function myFilter(&$service) { * <pre> function myFilter($service) {
* // Query $service object here. Return true if the service * // Query $service object here. Return true if the service
* // matches your query; false if not. * // matches your query; false if not.
* }</pre> * }</pre>
@ -207,7 +207,7 @@ function Auth_Yadis_getServiceEndpoints($input_url, $xrds_parse_func,
* this contrived example): * this contrived example):
* *
* <pre> * <pre>
* function URIMatcher(&$service) { * function URIMatcher($service) {
* foreach ($service->getElements('xrd:URI') as $uri) { * foreach ($service->getElements('xrd:URI') as $uri) {
* if (preg_match("/some_pattern/", * if (preg_match("/some_pattern/",
* $service->parser->content($uri))) { * $service->parser->content($uri))) {
@ -250,7 +250,7 @@ class Auth_Yadis_Yadis {
* If Auth_Yadis_CURL_OVERRIDE is defined, this method will always * If Auth_Yadis_CURL_OVERRIDE is defined, this method will always
* return a {@link Auth_Yadis_PlainHTTPFetcher}. * return a {@link Auth_Yadis_PlainHTTPFetcher}.
*/ */
function getHTTPFetcher($timeout = 20) static function getHTTPFetcher($timeout = 20)
{ {
if (Auth_Yadis_Yadis::curlPresent() && if (Auth_Yadis_Yadis::curlPresent() &&
(!defined('Auth_Yadis_CURL_OVERRIDE'))) { (!defined('Auth_Yadis_CURL_OVERRIDE'))) {
@ -261,7 +261,7 @@ class Auth_Yadis_Yadis {
return $fetcher; return $fetcher;
} }
function curlPresent() static function curlPresent()
{ {
return function_exists('curl_init'); return function_exists('curl_init');
} }
@ -269,7 +269,7 @@ class Auth_Yadis_Yadis {
/** /**
* @access private * @access private
*/ */
function _getHeader($header_list, $names) static function _getHeader($header_list, $names)
{ {
foreach ($header_list as $name => $value) { foreach ($header_list as $name => $value) {
foreach ($names as $n) { foreach ($names as $n) {
@ -285,7 +285,7 @@ class Auth_Yadis_Yadis {
/** /**
* @access private * @access private
*/ */
function _getContentType($content_type_header) static function _getContentType($content_type_header)
{ {
if ($content_type_header) { if ($content_type_header) {
$parts = explode(";", $content_type_header); $parts = explode(";", $content_type_header);
@ -317,7 +317,7 @@ class Auth_Yadis_Yadis {
* Auth_Yadis_Yadis, depending on whether the discovery * Auth_Yadis_Yadis, depending on whether the discovery
* succeeded. * succeeded.
*/ */
function discover($uri, &$fetcher, static function discover($uri, $fetcher,
$extra_ns_map = null, $timeout = 20) $extra_ns_map = null, $timeout = 20)
{ {
$result = new Auth_Yadis_DiscoveryResult($uri); $result = new Auth_Yadis_DiscoveryResult($uri);
@ -379,4 +379,4 @@ class Auth_Yadis_Yadis {
} }
} }
?>

View File

@ -54,6 +54,24 @@ class OAuthSignatureMethod {/*{{{*/
public function check_signature(&$request, $consumer, $token, $signature) { public function check_signature(&$request, $consumer, $token, $signature) {
$built = $this->build_signature($request, $consumer, $token); $built = $this->build_signature($request, $consumer, $token);
return $built == $signature; return $built == $signature;
// Check for zero length, although unlikely here
if (strlen($built) == 0 || strlen($signature) == 0) {
return false;
}
if (strlen($built) != strlen($signature)) {
return false;
}
$result = 0;
// Avoid a timing leak with a (hopefully) time insensitive compare
for ($i = 0; $i < strlen($signature); $i++) {
$result |= ord($built{$i}) ^ ord($signature{$i});
}
return $result == 0;
} }
}/*}}}*/ }/*}}}*/

View File

@ -1,14 +1,6 @@
<?php <?php
require_once 'xrds_mapper.php';
require_once 'constants.php';
/** /**
* Map XRDS actions to URLs using base URLs. * This file is part of libomb
*
* This interface specifies classes which write the XRDS file announcing
* the OMB server. An instance of an implementing class should be passed to
* OMB_Service_Provider->writeXRDS.
* *
* PHP version 5 * PHP version 5
* *
@ -25,27 +17,56 @@ require_once 'constants.php';
* You should have received a copy of the GNU Affero General Public License * 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/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
* @package OMB * @package OMB
* @author Adrian Lang <mail@adrianlang.de> * @author Adrian Lang <mail@adrianlang.de>
* @copyright 2009 Adrian Lang * @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
* @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0 * @version 0.1a-20090828
**/ * @link http://adrianlang.de/libomb
*/
class OMB_Base_URL_XRDS_Mapper implements OMB_XRDS_Mapper { require_once 'xrds_mapper.php';
require_once 'constants.php';
protected $urls; /**
* Map XRDS actions to URLs using base URLs
*
* This class realizes a simple mapping of action URIs to handler URLs. The
* target URLs are constructed using a base URL.
*/
class OMB_Base_URL_XRDS_Mapper implements OMB_XRDS_Mapper
{
protected $urls;
public function __construct($oauth_base, $omb_base) { /**
$this->urls = array( * Constructor
OAUTH_ENDPOINT_REQUEST => $oauth_base . 'requesttoken', *
OAUTH_ENDPOINT_AUTHORIZE => $oauth_base . 'userauthorization', * Initialize the XRDS mapper with base URLs for OAuth and OMB endpoints.
OAUTH_ENDPOINT_ACCESS => $oauth_base . 'accesstoken', *
OMB_ENDPOINT_POSTNOTICE => $omb_base . 'postnotice', * @param string $oauth_base The base URL for OAuth endpoints
OMB_ENDPOINT_UPDATEPROFILE => $omb_base . 'updateprofile'); * @param string $omb_base The base URL for OMB endpoints
} */
public function __construct($oauth_base, $omb_base)
{
$this->urls = array(
OAUTH_ENDPOINT_REQUEST => $oauth_base . 'requesttoken',
OAUTH_ENDPOINT_AUTHORIZE => $oauth_base . 'userauthorization',
OAUTH_ENDPOINT_ACCESS => $oauth_base . 'accesstoken',
OMB_ENDPOINT_POSTNOTICE => $omb_base . 'postnotice',
OMB_ENDPOINT_UPDATEPROFILE => $omb_base . 'updateprofile');
}
public function getURL($action) { /**
return $this->urls[$action]; * Fetch an URL for a specified action
} *
* Returns the action URL for an action specified by the endpoint URI.
*
* @param string $action The endpoint URI
*
* @return string The action URL
*/
public function getURL($action)
{
return $this->urls[$action];
}
} }
?> ?>

View File

@ -20,15 +20,16 @@
* You should have received a copy of the GNU Affero General Public License * 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/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
* @package OMB * @package OMB
* @author Adrian Lang <mail@adrianlang.de> * @author Adrian Lang <mail@adrianlang.de>
* @copyright 2009 Adrian Lang * @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
* @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0 * @version 0.1a-20090828
**/ * @link http://adrianlang.de/libomb
*/
/** /**
* The OMB constants. * The OMB constants.
**/ */
define('OMB_VERSION_01', 'http://openmicroblogging.org/protocol/0.1'); define('OMB_VERSION_01', 'http://openmicroblogging.org/protocol/0.1');
@ -40,7 +41,7 @@ define('OMB_ENDPOINT_POSTNOTICE', OMB_VERSION . '/postNotice');
/** /**
* The OAuth constants. * The OAuth constants.
**/ */
define('OAUTH_NAMESPACE', 'http://oauth.net/core/1.0/'); define('OAUTH_NAMESPACE', 'http://oauth.net/core/1.0/');

View File

@ -1,4 +1,28 @@
<?php <?php
/**
* This file is part of libomb
*
* PHP version 5
*
* LICENSE: 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/>.
*
* @package OMB
* @author Adrian Lang <mail@adrianlang.de>
* @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
* @version 0.1a-20090828
* @link http://adrianlang.de/libomb
*/
require_once 'OAuth.php'; require_once 'OAuth.php';
@ -27,174 +51,162 @@ require_once 'OAuth.php';
* Most of the parameters passed to these methods are unescaped and unverified * Most of the parameters passed to these methods are unescaped and unverified
* user input. Therefore they should be handled with extra care to avoid * user input. Therefore they should be handled with extra care to avoid
* security problems like SQL injections. * security problems like SQL injections.
* */
* PHP version 5 class OMB_Datastore extends OAuthDataStore
* {
* LICENSE: 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/>.
*
* @package OMB
* @author Adrian Lang <mail@adrianlang.de>
* @copyright 2009 Adrian Lang
* @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
**/
class OMB_Datastore extends OAuthDataStore { /*********
* OAUTH *
*********/
/********* /**
* OAUTH * * Revoke specified OAuth token
*********/ *
* Revokes the authorization token specified by $token_key.
* Throws exceptions in case of error.
*
* @param string $token_key The key of the token to be revoked
*
* @access public
*/
public function revoke_token($token_key)
{
throw new Exception();
}
/** /**
* Revoke specified OAuth token * Authorize specified OAuth token
* *
* Revokes the authorization token specified by $token_key. * Authorizes the authorization token specified by $token_key.
* Throws exceptions in case of error. * Throws exceptions in case of error.
* *
* @param string $token_key The key of the token to be revoked * @param string $token_key The key of the token to be authorized
* *
* @access public * @access public
**/ */
public function revoke_token($token_key) { public function authorize_token($token_key)
throw new Exception(); {
} throw new Exception();
}
/** /*********
* Authorize specified OAuth token * OMB *
* *********/
* Authorizes the authorization token specified by $token_key.
* Throws exceptions in case of error.
*
* @param string $token_key The key of the token to be authorized
*
* @access public
**/
public function authorize_token($token_key) {
throw new Exception();
}
/********* /**
* OMB * * Get profile by identifying URI
*********/ *
* Returns an OMB_Profile object representing the OMB profile identified by
* $identifier_uri.
* Returns null if there is no such OMB profile.
* Throws exceptions in case of other error.
*
* @param string $identifier_uri The OMB identifier URI specifying the
* requested profile
*
* @access public
*
* @return OMB_Profile The corresponding profile
*/
public function getProfile($identifier_uri)
{
throw new Exception();
}
/** /**
* Get profile by identifying URI * Save passed profile
* *
* Returns an OMB_Profile object representing the OMB profile identified by * Stores the OMB profile $profile. Overwrites an existing entry.
* $identifier_uri. * Throws exceptions in case of error.
* Returns null if there is no such OMB profile. *
* Throws exceptions in case of other error. * @param OMB_Profile $profile The OMB profile which should be saved
* *
* @param string $identifier_uri The OMB identifier URI specifying the * @access public
* requested profile */
* public function saveProfile($profile)
* @access public {
* throw new Exception();
* @return OMB_Profile The corresponding profile }
**/
public function getProfile($identifier_uri) {
throw new Exception();
}
/** /**
* Save passed profile * Save passed notice
* *
* Stores the OMB profile $profile. Overwrites an existing entry. * Stores the OMB notice $notice. The datastore may change the passed
* Throws exceptions in case of error. * notice. This might by necessary for URIs depending on a database key.
* * Note that it is the users duty to present a mechanism for his
* @param OMB_Profile $profile The OMB profile which should be saved * OMB_Datastore to appropriately change his OMB_Notice.
* * Throws exceptions in case of error.
* @access public *
**/ * @param OMB_Notice &$notice The OMB notice which should be saved
public function saveProfile($profile) { *
throw new Exception(); * @access public
} */
public function saveNotice(&$notice)
{
throw new Exception();
}
/** /**
* Save passed notice * Get subscriptions of a given profile
* *
* Stores the OMB notice $notice. The datastore may change the passed notice. * Returns an array containing subscription informations for the specified
* This might by neccessary for URIs depending on a database key. Note that * profile. Every array entry should in turn be an array with keys
* it is the users duty to present a mechanism for his OMB_Datastore to * 'uri´: The identifier URI of the subscriber
* appropriately change his OMB_Notice. TODO: Ugly. * 'token´: The subscribe token
* Throws exceptions in case of error. * 'secret´: The secret token
* * Throws exceptions in case of error.
* @param OMB_Notice $notice The OMB notice which should be saved *
* * @param string $subscribed_user_uri The OMB identifier URI specifying the
* @access public * subscribed profile
**/ *
public function saveNotice(&$notice) { * @access public
throw new Exception(); *
} * @return mixed An array containing the subscriptions or 0 if no
* subscription has been found.
*/
public function getSubscriptions($subscribed_user_uri)
{
throw new Exception();
}
/** /**
* Get subscriptions of a given profile * Delete a subscription
* *
* Returns an array containing subscription informations for the specified * Deletes the subscription from $subscriber_uri to $subscribed_user_uri.
* profile. Every array entry should in turn be an array with keys * Throws exceptions in case of error.
* 'uri´: The identifier URI of the subscriber *
* 'token´: The subscribe token * @param string $subscriber_uri The OMB identifier URI specifying the
* 'secret´: The secret token * subscribing profile
* Throws exceptions in case of error. *
* * @param string $subscribed_user_uri The OMB identifier URI specifying the
* @param string $subscribed_user_uri The OMB identifier URI specifying the * subscribed profile
* subscribed profile *
* * @access public
* @access public */
* public function deleteSubscription($subscriber_uri, $subscribed_user_uri)
* @return mixed An array containing the subscriptions or 0 if no {
* subscription has been found. throw new Exception();
**/ }
public function getSubscriptions($subscribed_user_uri) {
throw new Exception();
}
/** /**
* Delete a subscription * Save a subscription
* *
* Deletes the subscription from $subscriber_uri to $subscribed_user_uri. * Saves the subscription from $subscriber_uri to $subscribed_user_uri.
* Throws exceptions in case of error. * Throws exceptions in case of error.
* *
* @param string $subscriber_uri The OMB identifier URI specifying the * @param string $subscriber_uri The OMB identifier URI specifying
* subscribing profile * the subscribing profile
* *
* @param string $subscribed_user_uri The OMB identifier URI specifying the * @param string $subscribed_user_uri The OMB identifier URI specifying
* subscribed profile * the subscribed profile
* * @param OAuthToken $token The access token
* @access public *
**/ * @access public
public function deleteSubscription($subscriber_uri, $subscribed_user_uri) { */
throw new Exception(); public function saveSubscription($subscriber_uri, $subscribed_user_uri,
} $token)
{
/** throw new Exception();
* Save a subscription }
*
* Saves the subscription from $subscriber_uri to $subscribed_user_uri.
* Throws exceptions in case of error.
*
* @param string $subscriber_uri The OMB identifier URI specifying
* the subscribing profile
*
* @param string $subscribed_user_uri The OMB identifier URI specifying
* the subscribed profile
* @param OAuthToken $token The access token
*
* @access public
**/
public function saveSubscription($subscriber_uri, $subscribed_user_uri,
$token) {
throw new Exception();
}
} }
?> ?>

View File

@ -1,11 +1,6 @@
<?php <?php
require_once 'Validate.php';
/** /**
* Helper functions for libomb * This file is part of libomb
*
* This file contains helper functions for libomb.
* *
* PHP version 5 * PHP version 5
* *
@ -22,78 +17,88 @@ require_once 'Validate.php';
* You should have received a copy of the GNU Affero General Public License * 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/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
* @package OMB * @package OMB
* @author Adrian Lang <mail@adrianlang.de> * @author Adrian Lang <mail@adrianlang.de>
* @copyright 2009 Adrian Lang * @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
* @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0 * @version 0.1a-20090828
**/ * @link http://adrianlang.de/libomb
*/
class OMB_Helper { require_once 'Validate.php';
/** /**
* Non-scalar constants * Helper functions for libomb
* *
* The set of OMB and OAuth Services an OMB Server has to implement. * This class contains helper functions for libomb.
*/ */
class OMB_Helper
{
public static $OMB_SERVICES = /**
array(OMB_ENDPOINT_UPDATEPROFILE, OMB_ENDPOINT_POSTNOTICE); * Non-scalar constants
public static $OAUTH_SERVICES = *
array(OAUTH_ENDPOINT_REQUEST, OAUTH_ENDPOINT_AUTHORIZE, OAUTH_ENDPOINT_ACCESS); * The set of OMB and OAuth Services an OMB Server has to implement.
*/
/** public static $OMB_SERVICES = array(OMB_ENDPOINT_UPDATEPROFILE,
* Validate URL OMB_ENDPOINT_POSTNOTICE);
* public static $OAUTH_SERVICES = array(OAUTH_ENDPOINT_REQUEST,
* Basic URL validation. Currently http, https, ftp and gopher are supported OAUTH_ENDPOINT_AUTHORIZE,
* schemes. OAUTH_ENDPOINT_ACCESS);
*
* @param string $url The URL which is to be validated.
*
* @return bool Whether URL is valid.
*
* @access public
*/
public static function validateURL($url) {
return Validate::uri($url, array('allowed_schemes' => array('http', 'https',
'gopher', 'ftp')));
}
/** /**
* Validate Media type * Validate URL
* *
* Basic Media type validation. Checks for valid maintype and correct format. * Basic URL validation. Currently http, https, ftp and gopher are supported
* * schemes.
* @param string $mediatype The Media type which is to be validated. *
* * @param string $url The URL which is to be validated.
* @return bool Whether media type is valid. *
* * @return bool Whether URL is valid.
* @access public *
*/ * @access public
public static function validateMediaType($mediatype) { */
if (0 === preg_match('/^(\w+)\/([\w\d-+.]+)$/', $mediatype, $subtypes)) { public static function validateURL($url)
return false; {
return Validate::uri($url, array('allowed_schemes' => array('http',
'https', 'gopher', 'ftp')));
} }
if (!in_array(strtolower($subtypes[1]), array('application', 'audio', 'image',
'message', 'model', 'multipart', 'text', 'video'))) {
return false;
}
return true;
}
/** /**
* Remove escaping from request parameters * Validate Media type
* *
* Neutralise the evil effects of magic_quotes_gpc in the current request. * Basic Media type validation. Checks for valid maintype and correct
* This is used before handing a request off to OAuthRequest::from_request. * format.
* Many thanks to Ciaran Gultnieks for this fix. *
* * @param string $mediatype The Media type which is to be validated.
* @access public *
*/ * @return bool Whether media type is valid.
public static function removeMagicQuotesFromRequest() { *
if(get_magic_quotes_gpc() == 1) { * @access public
$_POST = array_map('stripslashes', $_POST); */
$_GET = array_map('stripslashes', $_GET); public static function validateMediaType($mediatype)
{
return preg_match('/^(\w+)\/([\w\d-+.]+)$/', $mediatype, $subtypes) > 0
&&
in_array(strtolower($subtypes[1]), array('application', 'audio',
'image', 'message', 'model', 'multipart', 'text', 'video'));
}
/**
* Remove escaping from request parameters
*
* Neutralise the evil effects of magic_quotes_gpc in the current request.
* This is used before handing a request off to OAuthRequest::from_request.
* Many thanks to Ciaran Gultnieks for this fix.
*
* @access public
*/
public static function removeMagicQuotesFromRequest()
{
if (get_magic_quotes_gpc() === 1) {
$_POST = array_map('stripslashes', $_POST);
$_GET = array_map('stripslashes', $_GET);
}
} }
}
} }
?> ?>

View File

@ -1,8 +1,6 @@
<?php <?php
/** /**
* Exception stating that a passed parameter is invalid * This file is part of libomb
*
* This exception is raised when a parameter does not obey the OMB standard.
* *
* PHP version 5 * PHP version 5
* *
@ -19,14 +17,36 @@
* You should have received a copy of the GNU Affero General Public License * 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/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
* @package OMB * @package OMB
* @author Adrian Lang <mail@adrianlang.de> * @author Adrian Lang <mail@adrianlang.de>
* @copyright 2009 Adrian Lang * @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
* @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0 * @version 0.1a-20090828
**/ * @link http://adrianlang.de/libomb
class OMB_InvalidParameterException extends Exception { */
public function __construct($value, $type, $parameter) {
parent::__construct("Invalid value $value for parameter $parameter in $type"); /**
} * Exception stating that a passed parameter is invalid
*
* This exception is raised when a parameter does not obey the OMB standard.
*/
class OMB_InvalidParameterException extends Exception
{
/**
* Constructor
*
* Creates a new exception based on a parameter name, value, and object
* type.
*
* @param string $value The wrong value passed
* @param string $type The object type the parameter belongs to;
* Currently OMB uses profiles and notices
* @param string $parameter The name of the parameter the wrong value has
* been passed for
*/
public function __construct($value, $type, $parameter)
{
parent::__construct("Invalid value ${value} for parameter " .
"${parameter} in $type");
}
} }
?> ?>

View File

@ -1,9 +1,6 @@
<?php <?php
/** /**
* Exception stating that a requested url does not resolve to a valid yadis * This file is part of libomb
*
* This exception is raised when OMB_Service is not able to discover a valid
* yadis location with XRDS.
* *
* PHP version 5 * PHP version 5
* *
@ -20,12 +17,21 @@
* You should have received a copy of the GNU Affero General Public License * 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/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
* @package OMB * @package OMB
* @author Adrian Lang <mail@adrianlang.de> * @author Adrian Lang <mail@adrianlang.de>
* @copyright 2009 Adrian Lang * @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
* @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0 * @version 0.1a-20090828
**/ * @link http://adrianlang.de/libomb
class OMB_InvalidYadisException extends Exception { */
/**
* Exception stating that a requested url does not resolve to a valid yadis
*
* This exception is raised when OMB_Service is not able to discover a valid
* yadis location with XRDS.
*/
class OMB_InvalidYadisException extends Exception
{
} }
?> ?>

View File

@ -1,15 +1,6 @@
<?php <?php
require_once 'invalidparameterexception.php';
require_once 'Validate.php';
require_once 'helper.php';
/** /**
* OMB Notice representation * This file is part of libomb
*
* This class represents an OMB notice.
*
* Do not call the setters with null values. Instead, if you want to delete a
* field, pass an empty string. The getters will return null for empty fields.
* *
* PHP version 5 * PHP version 5
* *
@ -26,247 +17,278 @@ require_once 'helper.php';
* You should have received a copy of the GNU Affero General Public License * 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/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
* @package OMB * @package OMB
* @author Adrian Lang <mail@adrianlang.de> * @author Adrian Lang <mail@adrianlang.de>
* @copyright 2009 Adrian Lang * @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
* @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0 * @version 0.1a-20090828
**/ * @link http://adrianlang.de/libomb
*/
class OMB_Notice { require_once 'invalidparameterexception.php';
protected $author; require_once 'Validate.php';
protected $uri; require_once 'helper.php';
protected $content;
protected $url;
protected $license_url; /* url is an own addition for clarification. */
protected $seealso_url; /* url is an own addition for clarification. */
protected $seealso_disposition;
protected $seealso_mediatype;
protected $seealso_license_url; /* url is an addition for clarification. */
/* The notice as OMB param array. Cached and rebuild on usage. /**
false while outdated. */ * OMB Notice representation
protected $param_array; *
* This class represents an OMB notice.
*
* Do not call the setters with null values. Instead, if you want to delete a
* field, pass an empty string. The getters will return null for empty fields.
*/
class OMB_Notice
{
protected $author;
protected $uri;
protected $content;
protected $url;
protected $license_url; /* url is an own addition for clarification. */
protected $seealso_url; /* url is an own addition for clarification. */
protected $seealso_disposition;
protected $seealso_mediatype;
protected $seealso_license_url; /* url is an addition for clarification. */
/** /* The notice as OMB param array. Cached and rebuild on usage.
* Constructor for OMB_Notice false while outdated. */
* protected $param_array;
* Initializes the OMB_Notice object with author, uri and content.
* These parameters are mandatory for postNotice.
*
* @param object $author An OMB_Profile object representing the author of the
* notice.
* @param string $uri The notice URI as defined by the OMB. A unique and
* unchanging identifier for a notice.
* @param string $content The content of the notice. 140 chars recommended,
* but there is no limit.
*
* @access public
*/
public function __construct($author, $uri, $content) {
$this->content = $content;
if (is_null($author)) {
throw new OMB_InvalidParameterException('', 'notice', 'omb_listenee');
}
$this->author = $author;
if (!Validate::uri($uri)) { /**
throw new OMB_InvalidParameterException($uri, 'notice', 'omb_notice'); * Constructor for OMB_Notice
} *
$this->uri = $uri; * Initializes the OMB_Notice object with author, uri and content.
* These parameters are mandatory for postNotice.
*
* @param object $author An OMB_Profile object representing the author of
* the notice.
* @param string $uri The notice URI as defined by the OMB. A unique and
* never changing identifier for a notice.
* @param string $content The content of the notice. 140 chars recommended,
* but there is no limit.
*
* @access public
*/
public function __construct($author, $uri, $content)
{
$this->content = $content;
if (is_null($author)) {
throw new OMB_InvalidParameterException('', 'notice', 'omb_listenee');
}
$this->author = $author;
$this->param_array = false; if (!Validate::uri($uri)) {
} throw new OMB_InvalidParameterException($uri, 'notice', 'omb_notice');
}
$this->uri = $uri;
/** $this->param_array = false;
* Returns the notice as array
*
* The method returns an array which contains the whole notice as array. The
* array is cached and only rebuilt on changes of the notice.
* Empty optional values are not passed.
*
* @access public
* @returns array The notice as parameter array
*/
public function asParameters() {
if ($this->param_array !== false) {
return $this->param_array;
} }
$this->param_array = array( /**
'omb_notice' => $this->uri, * Return the notice as array
'omb_notice_content' => $this->content); *
* Returns an array which contains the whole notice as array. The array is
* cached and only rebuilt on changes of the notice.
* Empty optional values are not passed.
*
* @access public
* @return array The notice as parameter array
*/
public function asParameters()
{
if ($this->param_array !== false) {
return $this->param_array;
}
if (!is_null($this->url)) $this->param_array = array(
$this->param_array['omb_notice_url'] = $this->url; 'omb_notice' => $this->uri,
'omb_notice_content' => $this->content);
if (!is_null($this->license_url)) if (!is_null($this->url))
$this->param_array['omb_notice_license'] = $this->license_url; $this->param_array['omb_notice_url'] = $this->url;
if (!is_null($this->seealso_url)) { if (!is_null($this->license_url))
$this->param_array['omb_seealso'] = $this->seealso_url; $this->param_array['omb_notice_license'] = $this->license_url;
/* This is actually a free interpretation of the OMB standard. We assume if (!is_null($this->seealso_url)) {
that additional seealso parameters are not of any use if seealso itself $this->param_array['omb_seealso'] = $this->seealso_url;
is not set. */
if (!is_null($this->seealso_disposition)) /* This is actually a free interpretation of the OMB standard. We
$this->param_array['omb_seealso_disposition'] = assume that additional seealso parameters are not of any use if
seealso itself is not set. */
if (!is_null($this->seealso_disposition))
$this->param_array['omb_seealso_disposition'] =
$this->seealso_disposition; $this->seealso_disposition;
if (!is_null($this->seealso_mediatype)) if (!is_null($this->seealso_mediatype))
$this->param_array['omb_seealso_mediatype'] = $this->seealso_mediatype; $this->param_array['omb_seealso_mediatype'] =
$this->seealso_mediatype;
if (!is_null($this->seealso_license_url)) if (!is_null($this->seealso_license_url))
$this->param_array['omb_seealso_license'] = $this->seealso_license_url; $this->param_array['omb_seealso_license'] =
} $this->seealso_license_url;
return $this->param_array; }
} return $this->param_array;
/**
* Builds an OMB_Notice object from array
*
* The method builds an OMB_Notice object from the passed parameters array.
* The array MUST provide a notice URI and content. The array fields HAVE TO
* be named according to the OMB standard, i. e. omb_notice_* and
* omb_seealso_*. Values are handled as not passed if the corresponding array
* fields are not set or the empty string.
*
* @param object $author An OMB_Profile object representing the author of
* the notice.
* @param string $parameters An array containing the notice parameters.
*
* @access public
*
* @returns OMB_Notice The built OMB_Notice.
*/
public static function fromParameters($author, $parameters) {
$notice = new OMB_Notice($author, $parameters['omb_notice'],
$parameters['omb_notice_content']);
if (isset($parameters['omb_notice_url'])) {
$notice->setURL($parameters['omb_notice_url']);
} }
if (isset($parameters['omb_notice_license'])) { /**
$notice->setLicenseURL($parameters['omb_notice_license']); * Build an OMB_Notice object from array
*
* Builds an OMB_Notice object from the passed parameters array. The array
* MUST provide a notice URI and content. The array fields HAVE TO be named
* according to the OMB standard, i. e. omb_notice_* and omb_seealso_*.
* Values are handled as not passed if the corresponding array fields are
* not set or the empty string.
*
* @param object $author An OMB_Profile object representing the author
* of the notice.
* @param string $parameters An array containing the notice parameters.
*
* @access public
*
* @returns OMB_Notice The built OMB_Notice.
*/
public static function fromParameters($author, $parameters)
{
$notice = new OMB_Notice($author, $parameters['omb_notice'],
$parameters['omb_notice_content']);
if (isset($parameters['omb_notice_url'])) {
$notice->setURL($parameters['omb_notice_url']);
}
if (isset($parameters['omb_notice_license'])) {
$notice->setLicenseURL($parameters['omb_notice_license']);
}
if (isset($parameters['omb_seealso'])) {
$notice->setSeealsoURL($parameters['omb_seealso']);
}
if (isset($parameters['omb_seealso_disposition'])) {
$notice->setSeealsoDisposition($parameters['omb_seealso_disposition']);
}
if (isset($parameters['omb_seealso_mediatype'])) {
$notice->setSeealsoMediatype($parameters['omb_seealso_mediatype']);
}
if (isset($parameters['omb_seealso_license'])) {
$notice->setSeealsoLicenseURL($parameters['omb_seealso_license']);
}
return $notice;
} }
if (isset($parameters['omb_seealso'])) { public function getAuthor()
$notice->setSeealsoURL($parameters['omb_seealso']); {
return $this->author;
} }
if (isset($parameters['omb_seealso_disposition'])) { public function getIdentifierURI()
$notice->setSeealsoDisposition($parameters['omb_seealso_disposition']); {
return $this->uri;
} }
if (isset($parameters['omb_seealso_mediatype'])) { public function getContent()
$notice->setSeealsoMediatype($parameters['omb_seealso_mediatype']); {
return $this->content;
} }
if (isset($parameters['omb_seealso_license'])) { public function getURL()
$notice->setSeealsoLicenseURL($parameters['omb_seealso_license']); {
return $this->url;
} }
return $notice;
}
public function getAuthor() { public function getLicenseURL()
return $this->author; {
} return $this->license_url;
public function getIdentifierURI() {
return $this->uri;
}
public function getContent() {
return $this->content;
}
public function getURL() {
return $this->url;
}
public function getLicenseURL() {
return $this->license_url;
}
public function getSeealsoURL() {
return $this->seealso_url;
}
public function getSeealsoDisposition() {
return $this->seealso_disposition;
}
public function getSeealsoMediatype() {
return $this->seealso_mediatype;
}
public function getSeealsoLicenseURL() {
return $this->seealso_license_url;
}
public function setURL($url) {
if ($url === '') {
$url = null;
} elseif (!OMB_Helper::validateURL($url)) {
throw new OMB_InvalidParameterException($url, 'notice', 'omb_notice_url');
} }
$this->url = $url;
$this->param_array = false;
}
public function setLicenseURL($license_url) { public function getSeealsoURL()
if ($license_url === '') { {
$license_url = null; return $this->seealso_url;
} elseif (!OMB_Helper::validateURL($license_url)) {
throw new OMB_InvalidParameterException($license_url, 'notice',
'omb_notice_license');
} }
$this->license_url = $license_url;
$this->param_array = false;
}
public function setSeealsoURL($seealso_url) { public function getSeealsoDisposition()
if ($seealso_url === '') { {
$seealso_url = null; return $this->seealso_disposition;
} elseif (!OMB_Helper::validateURL($seealso_url)) {
throw new OMB_InvalidParameterException($seealso_url, 'notice',
'omb_seealso');
} }
$this->seealso_url = $seealso_url;
$this->param_array = false;
}
public function setSeealsoDisposition($seealso_disposition) { public function getSeealsoMediatype()
if ($seealso_disposition === '') { {
$seealso_disposition = null; return $this->seealso_mediatype;
} elseif ($seealso_disposition !== 'link' && $seealso_disposition !== 'inline') {
throw new OMB_InvalidParameterException($seealso_disposition, 'notice',
'omb_seealso_disposition');
} }
$this->seealso_disposition = $seealso_disposition;
$this->param_array = false;
}
public function setSeealsoMediatype($seealso_mediatype) { public function getSeealsoLicenseURL()
if ($seealso_mediatype === '') { {
$seealso_mediatype = null; return $this->seealso_license_url;
} elseif (!OMB_Helper::validateMediaType($seealso_mediatype)) {
throw new OMB_InvalidParameterException($seealso_mediatype, 'notice',
'omb_seealso_mediatype');
} }
$this->seealso_mediatype = $seealso_mediatype;
$this->param_array = false;
}
public function setSeealsoLicenseURL($seealso_license_url) { public function setURL($url)
if ($seealso_license_url === '') { {
$seealso_license_url = null; $this->setVal('notice_url', $url, 'OMB_Helper::validateURL', 'url');
} elseif (!OMB_Helper::validateURL($seealso_license_url)) { }
throw new OMB_InvalidParameterException($seealso_license_url, 'notice',
'omb_seealso_license'); public function setLicenseURL($license_url)
{
$this->setVal('license', $license_url, 'OMB_Helper::validateURL',
'license_url');
}
public function setSeealsoURL($seealso_url)
{
$this->setVal('seealso', $seealso_url, 'OMB_Helper::validateURL',
'seealso_url');
}
public function setSeealsoDisposition($seealso_disposition)
{
$this->setVal('seealso_disposition', $seealso_disposition,
'OMB_Notice::validateDisposition');
}
protected static function validateDisposition($str)
{
return in_array($str, array('link', 'inline'));
}
public function setSeealsoMediatype($seealso_mediatype)
{
$this->setVal('seealso_mediatype', $seealso_mediatype,
'OMB_Helper::validateMediaType');
}
public function setSeealsoLicenseURL($seealso_license_url)
{
$this->setVal('seealso_license', $seealso_license_url,
'OMB_Helper::validateURL', 'seealso_license_url');
}
/**
* Set a value
*
* Updates a value specified by a parameter name and the new value.
*
* @param string $param The parameter name according to OMB
* @param string $value The new value
* @param callback $validator A validator function for the parameter
* @param string $field The name of the field in OMB_Notice
* @param bool $force Whether null values should be checked as well
*/
protected function setVal($param, $value, $validator, $field = null,
$force = false)
{
if (is_null($field)) {
$field = $param;
}
if ($value === '' && !$force) {
$value = null;
} elseif (!call_user_func($validator, $value)) {
throw new OMB_InvalidParameterException($value, 'notice', $param);
}
if ($this->$field !== $value) {
$this->$field = $value;
$this->param_array = false;
}
} }
$this->seealso_license_url = $seealso_license_url;
$this->param_array = false;
}
} }
?> ?>

View File

@ -1,14 +1,6 @@
<?php <?php
require_once 'Auth/Yadis/Yadis.php';
require_once 'unsupportedserviceexception.php';
require_once 'invalidyadisexception.php';
/** /**
* OMB XRDS representation * This file is part of libomb
*
* This class represents a Yadis XRDS file for OMB. It adds some useful methods to
* Auth_Yadis_XRDS.
* *
* PHP version 5 * PHP version 5
* *
@ -25,172 +17,193 @@ require_once 'invalidyadisexception.php';
* You should have received a copy of the GNU Affero General Public License * 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/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
* @package OMB * @package OMB
* @author Adrian Lang <mail@adrianlang.de> * @author Adrian Lang <mail@adrianlang.de>
* @copyright 2009 Adrian Lang * @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
* @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0 * @version 0.1a-20090828
**/ * @link http://adrianlang.de/libomb
*/
class OMB_Yadis_XRDS extends Auth_Yadis_XRDS { require_once 'Auth/Yadis/Yadis.php';
require_once 'unsupportedserviceexception.php';
require_once 'invalidyadisexception.php';
protected $fetcher; /**
* OMB XRDS representation
*
* This class represents a Yadis XRDS file for OMB. It adds some useful methods to
* Auth_Yadis_XRDS.
*/
class OMB_Yadis_XRDS extends Auth_Yadis_XRDS
{
/** protected $fetcher;
* Create an instance from URL
* /**
* Constructs an OMB_Yadis_XRDS object from a given URL. A full Yadis * Create an instance from URL
* discovery is performed on the URL and the XRDS is parsed. *
* Throws an OMB_InvalidYadisException when no Yadis is discovered or the * Constructs an OMB_Yadis_XRDS object from a given URL. A full Yadis
* detected XRDS file is broken. * discovery is performed on the URL and the XRDS is parsed.
* * Throws an OMB_InvalidYadisException when no Yadis is discovered or the
* @param string $url The URL on which Yadis discovery * detected XRDS file is broken.
* should be performed on *
* @param Auth_Yadis_HTTPFetcher $fetcher A fetcher used to get HTTP * @param string $url The URL on which Yadis discovery
* resources * should be performed on
* * @param Auth_Yadis_HTTPFetcher $fetcher A fetcher used to get HTTP
* @access public * resources
* *
* @return OMB_Yadis_XRDS The initialized object representing the given * @access public
* resource *
**/ * @return OMB_Yadis_XRDS The initialized object representing the given
public static function fromYadisURL($url, $fetcher) { * resource
/* Perform a Yadis discovery. */ */
$yadis = Auth_Yadis_Yadis::discover($url, $fetcher); public static function fromYadisURL($url, $fetcher)
if ($yadis->failed) { {
throw new OMB_InvalidYadisException($url); /* Perform a Yadis discovery. */
$yadis = Auth_Yadis_Yadis::discover($url, $fetcher);
if ($yadis->failed) {
throw new OMB_InvalidYadisException($url);
}
/* Parse the XRDS file. */
$xrds = OMB_Yadis_XRDS::parseXRDS($yadis->response_text);
if ($xrds === null) {
throw new OMB_InvalidYadisException($url);
}
$xrds->fetcher = $fetcher;
return $xrds;
} }
/* Parse the XRDS file. */ /**
$xrds = OMB_Yadis_XRDS::parseXRDS($yadis->response_text); * Get a specific service
if ($xrds === null) { *
throw new OMB_InvalidYadisException($url); * Returns the Auth_Yadis_Service object corresponding to the given service
} * URI.
$xrds->fetcher = $fetcher; * Throws an OMB_UnsupportedServiceException if the service is not
return $xrds; * available.
} *
* @param string $service URI specifier of the requested service
/** *
* Get a specific service * @access public
* *
* Returns the Auth_Yadis_Service object corresponding to the given service * @return Auth_Yadis_Service The object representing the requested service
* URI. */
* Throws an OMB_UnsupportedServiceException if the service is not available. public function getService($service)
* {
* @param string $service URI specifier of the requested service $match = $this->services(array(create_function('$s',
* "return in_array('$service', \$s->getTypes());")));
* @access public if ($match === array()) {
* throw new OMB_UnsupportedServiceException($service);
* @return Auth_Yadis_Service The object representing the requested service }
**/ return $match[0];
public function getService($service) {
$match = $this->services(array( create_function('$s',
"return in_array('$service', \$s->getTypes());")));
if ($match === array()) {
throw new OMB_UnsupportedServiceException($service);
}
return $match[0];
}
/**
* Get a specific XRD
*
* Returns the OMB_Yadis_XRDS object corresponding to the given URI.
* Throws an OMB_UnsupportedServiceException if the XRD is not available.
* Note that getXRD tries to resolve external XRD parts as well.
*
* @param string $uri URI specifier of the requested XRD
*
* @access public
*
* @return OMB_Yadis_XRDS The object representing the requested XRD
**/
public function getXRD($uri) {
$nexthash = strpos($uri, '#');
if ($nexthash !== 0) {
if ($nexthash !== false) {
$cururi = substr($uri, 0, $nexthash);
$nexturi = substr($uri, $nexthash);
}
return
OMB_Yadis_XRDS::fromYadisURL($cururi, $this->fetcher)->getXRD($nexturi);
} }
$id = substr($uri, 1); /**
foreach ($this->allXrdNodes as $node) { * Get a specific XRD
$attrs = $this->parser->attributes($node); *
if (array_key_exists('xml:id', $attrs) && $attrs['xml:id'] == $id) { * Returns the OMB_Yadis_XRDS object corresponding to the given URI.
/* Trick the constructor into thinking this is the only node. */ * Throws an OMB_UnsupportedServiceException if the XRD is not available.
$bogus_nodes = array($node); * Note that getXRD tries to resolve external XRD parts as well.
return new OMB_Yadis_XRDS($this->parser, $bogus_nodes); *
} * @param string $uri URI specifier of the requested XRD
} *
throw new OMB_UnsupportedServiceException($uri); * @access public
} *
* @return OMB_Yadis_XRDS The object representing the requested XRD
*/
public function getXRD($uri)
{
$nexthash = strpos($uri, '#');
if ($nexthash === false) {
throw new OMB_InvalidYadisException("$uri does not specify a " .
'valid XML node.');
}
/** if ($nexthash > 0) {
* Parse an XML string containing a XRDS document $cururi = substr($uri, 0, $nexthash);
* $nexturi = substr($uri, $nexthash);
* Parse an XML string (XRDS document) and return either a return OMB_Yadis_XRDS::fromYadisURL($cururi, $this->fetcher)
* Auth_Yadis_XRDS object or null, depending on whether the ->getXRD($nexturi);
* XRDS XML is valid. }
* Copy and paste from parent to select correct constructor.
*
* @param string $xml_string An XRDS XML string.
*
* @access public
*
* @return mixed An instance of OMB_Yadis_XRDS or null,
* depending on the validity of $xml_string
**/
public function &parseXRDS($xml_string, $extra_ns_map = null) { $id = substr($uri, 1);
$_null = null; foreach ($this->allXrdNodes as $node) {
$attrs = $this->parser->attributes($node);
if (!$xml_string) { if (array_key_exists('xml:id', $attrs) && $attrs['xml:id'] == $id) {
return $_null; /* Trick the constructor into thinking this is the only node. */
$bogus_nodes = array($node);
return new OMB_Yadis_XRDS($this->parser, $bogus_nodes);
}
}
throw new OMB_UnsupportedServiceException($uri);
} }
$parser = Auth_Yadis_getXMLParser(); /**
* Parse an XML string containing a XRDS document
*
* Parses an XML string (XRDS document) and returns either an
* Auth_Yadis_XRDS object or null, depending on whether the XRDS XML is
* valid.
* This method is just copy and paste from the parent class to select the
* correct constructor.
*
* @param string $xml_string An XRDS XML string
* @param array $extra_ns_map Additional namespace declarations
*
* @access public
*
* @return mixed An instance of OMB_Yadis_XRDS or null,
* depending on the validity of $xml_string
*/
public static function parseXRDS($xml_string, $extra_ns_map = null)
{
$_null = null;
$ns_map = Auth_Yadis_getNSMap(); if (!$xml_string) {
return $_null;
}
if ($extra_ns_map && is_array($extra_ns_map)) { $parser = Auth_Yadis_getXMLParser();
$ns_map = array_merge($ns_map, $extra_ns_map);
$ns_map = Auth_Yadis_getNSMap();
if ($extra_ns_map && is_array($extra_ns_map)) {
$ns_map = array_merge($ns_map, $extra_ns_map);
}
if (!($parser && $parser->init($xml_string, $ns_map))) {
return $_null;
}
// Try to get root element.
$root = $parser->evalXPath('/xrds:XRDS[1]');
if (!$root) {
return $_null;
}
if (is_array($root)) {
$root = $root[0];
}
$attrs = $parser->attributes($root);
if (array_key_exists('xmlns:xrd', $attrs) &&
$attrs['xmlns:xrd'] != Auth_Yadis_XMLNS_XRDS) {
return $_null;
} else if (array_key_exists('xmlns', $attrs) &&
preg_match('/xri/', $attrs['xmlns']) &&
$attrs['xmlns'] != Auth_Yadis_XMLNS_XRD_2_0) {
return $_null;
}
// Get the last XRD node.
$xrd_nodes = $parser->evalXPath('/xrds:XRDS[1]/xrd:XRD');
if (!$xrd_nodes) {
return $_null;
}
$xrds = new OMB_Yadis_XRDS($parser, $xrd_nodes);
return $xrds;
} }
if (!($parser && $parser->init($xml_string, $ns_map))) {
return $_null;
}
// Try to get root element.
$root = $parser->evalXPath('/xrds:XRDS[1]');
if (!$root) {
return $_null;
}
if (is_array($root)) {
$root = $root[0];
}
$attrs = $parser->attributes($root);
if (array_key_exists('xmlns:xrd', $attrs) &&
$attrs['xmlns:xrd'] != Auth_Yadis_XMLNS_XRDS) {
return $_null;
} else if (array_key_exists('xmlns', $attrs) &&
preg_match('/xri/', $attrs['xmlns']) &&
$attrs['xmlns'] != Auth_Yadis_XMLNS_XRD_2_0) {
return $_null;
}
// Get the last XRD node.
$xrd_nodes = $parser->evalXPath('/xrds:XRDS[1]/xrd:XRD');
if (!$xrd_nodes) {
return $_null;
}
$xrds = new OMB_Yadis_XRDS($parser, $xrd_nodes);
return $xrds;
}
} }

View File

@ -1,13 +1,6 @@
<?php <?php
require_once 'xrds_writer.php';
/** /**
* Write OMB-specific XRDS using XMLWriter. * This file is part of libomb
*
* This class writes the XRDS file announcing the OMB server. It uses
* OMB_XMLWriter, which is a subclass of XMLWriter. An instance of
* OMB_Plain_XRDS_Writer should be passed to OMB_Service_Provider->writeXRDS.
* *
* PHP version 5 * PHP version 5
* *
@ -24,25 +17,45 @@ require_once 'xrds_writer.php';
* You should have received a copy of the GNU Affero General Public License * 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/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
* @package OMB * @package OMB
* @author Adrian Lang <mail@adrianlang.de> * @author Adrian Lang <mail@adrianlang.de>
* @copyright 2009 Adrian Lang * @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
* @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0 * @version 0.1a-20090828
**/ * @link http://adrianlang.de/libomb
*/
class OMB_Plain_XRDS_Writer implements OMB_XRDS_Writer { require_once 'xrds_writer.php';
public function writeXRDS($user, $mapper) {
header('Content-Type: application/xrds+xml');
$xw = new XMLWriter();
$xw->openURI('php://output');
$xw->setIndent(true);
$xw->startDocument('1.0', 'UTF-8'); /**
$this->writeFullElement($xw, 'XRDS', array('xmlns' => 'xri://$xrds'), array( * Write OMB-specific XRDS using XMLWriter
array('XRD', array('xmlns' => 'xri://$xrd*($v*2.0)', *
'xml:id' => 'oauth', * This class writes the XRDS file announcing the OMB server. It uses XMLWriter.
'xmlns:simple' => 'http://xrds-simple.net/core/1.0', * An instance of OMB_Plain_XRDS_Writer should be passed to
'version' => '2.0'), array( * OMB_Service_Provider->writeXRDS.
*/
class OMB_Plain_XRDS_Writer implements OMB_XRDS_Writer
{
/**
* Write XRDS using XMLWriter
*
* Outputs a XRDS document specifying an OMB service.
*
* @param OMB_profile $user The target user for the OMB service
* @param OMB_XRDS_Mapper $mapper An OMB_XRDS_Mapper providing endpoint URLs
*/
public function writeXRDS($user, $mapper)
{
header('Content-Type: application/xrds+xml');
$xw = new XMLWriter();
$xw->openURI('php://output');
$xw->setIndent(true);
$xw->startDocument('1.0', 'UTF-8');
$this->_writeFullElement($xw, 'XRDS', array('xmlns' => 'xri://$xrds'), array(
array('XRD', array('xmlns' => 'xri://$xrd*($v*2.0)',
'xml:id' => 'oauth',
'xmlns:simple' => 'http://xrds-simple.net/core/1.0',
'version' => '2.0'), array(
array('Type', null, 'xri://$xrds*simple'), array('Type', null, 'xri://$xrds*simple'),
array('Service', null, array( array('Service', null, array(
array('Type', null, OAUTH_ENDPOINT_REQUEST), array('Type', null, OAUTH_ENDPOINT_REQUEST),
@ -73,10 +86,10 @@ class OMB_Plain_XRDS_Writer implements OMB_XRDS_Writer {
array('Type', null, OAUTH_HMAC_SHA1) array('Type', null, OAUTH_HMAC_SHA1)
)) ))
)), )),
array('XRD', array('xmlns' => 'xri://$xrd*($v*2.0)', array('XRD', array('xmlns' => 'xri://$xrd*($v*2.0)',
'xml:id' => 'omb', 'xml:id' => 'omb',
'xmlns:simple' => 'http://xrds-simple.net/core/1.0', 'xmlns:simple' => 'http://xrds-simple.net/core/1.0',
'version' => '2.0'), array( 'version' => '2.0'), array(
array('Type', null, 'xri://$xrds*simple'), array('Type', null, 'xri://$xrds*simple'),
array('Service', null, array( array('Service', null, array(
array('Type', null, OMB_ENDPOINT_POSTNOTICE), array('Type', null, OMB_ENDPOINT_POSTNOTICE),
@ -87,8 +100,8 @@ class OMB_Plain_XRDS_Writer implements OMB_XRDS_Writer {
array('URI', null, $mapper->getURL(OMB_ENDPOINT_UPDATEPROFILE)) array('URI', null, $mapper->getURL(OMB_ENDPOINT_UPDATEPROFILE))
)) ))
)), )),
array('XRD', array('xmlns' => 'xri://$xrd*($v*2.0)', array('XRD', array('xmlns' => 'xri://$xrd*($v*2.0)',
'version' => '2.0'), array( 'version' => '2.0'), array(
array('Type', null, 'xri://$xrds*simple'), array('Type', null, 'xri://$xrds*simple'),
array('Service', null, array( array('Service', null, array(
array('Type', null, OAUTH_DISCOVERY), array('Type', null, OAUTH_DISCOVERY),
@ -98,27 +111,40 @@ class OMB_Plain_XRDS_Writer implements OMB_XRDS_Writer {
array('Type', null, OMB_VERSION), array('Type', null, OMB_VERSION),
array('URI', null, '#omb') array('URI', null, '#omb')
)) ))
)) ))));
)); $xw->endDocument();
$xw->endDocument(); $xw->flush();
$xw->flush(); }
}
public static function writeFullElement($xw, $tag, $attributes, $content) { /**
$xw->startElement($tag); * Write a complex XML element
if (!is_null($attributes)) { *
foreach ($attributes as $name => $value) { * Outputs a XML element with attributes and content.
$xw->writeAttribute($name, $value); *
} * @param XMLWriter $xw The XMLWriter used to output the element
* @param string $tag The tag name
* @param array|null $attributes A map of XML attributes
* @param array|string $content The content of the element; either an
* array of child nodes each specified by a
* three entry-array ($tag, $attributes,
* $content) or a string
*/
private function _writeFullElement($xw, $tag, $attributes, $content)
{
$xw->startElement($tag);
if (!is_null($attributes)) {
foreach ($attributes as $name => $value) {
$xw->writeAttribute($name, $value);
}
}
if (is_array($content)) {
foreach ($content as $val) {
$this->_writeFullElement($xw, $val[0], $val[1], $val[2]);
}
} else {
$xw->text($content);
}
$xw->fullEndElement();
} }
if (is_array($content)) {
foreach ($content as $values) {
OMB_Plain_XRDS_Writer::writeFullElement($xw, $values[0], $values[1], $values[2]);
}
} else {
$xw->text($content);
}
$xw->fullEndElement();
}
} }
?> ?>

View File

@ -1,15 +1,6 @@
<?php <?php
require_once 'invalidparameterexception.php';
require_once 'Validate.php';
require_once 'helper.php';
/** /**
* OMB profile representation * This file is part of libomb
*
* This class represents an OMB profile.
*
* Do not call the setters with null values. Instead, if you want to delete a
* field, pass an empty string. The getters will return null for empty fields.
* *
* PHP version 5 * PHP version 5
* *
@ -26,292 +17,329 @@ require_once 'helper.php';
* You should have received a copy of the GNU Affero General Public License * 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/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
* @package OMB * @package OMB
* @author Adrian Lang <mail@adrianlang.de> * @author Adrian Lang <mail@adrianlang.de>
* @copyright 2009 Adrian Lang * @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
* @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0 * @version 0.1a-20090828
**/ * @link http://adrianlang.de/libomb
*/
class OMB_Profile { require_once 'invalidparameterexception.php';
protected $identifier_uri; require_once 'Validate.php';
protected $profile_url; require_once 'helper.php';
protected $nickname;
protected $license_url;
protected $fullname;
protected $homepage;
protected $bio;
protected $location;
protected $avatar_url;
/* The profile as OMB param array. Cached and rebuild on usage. /**
false while outdated. */ * OMB profile representation
protected $param_array; *
* This class represents an OMB profile.
*
* Do not call the setters with null values. Instead, if you want to delete a
* field, pass an empty string. The getters will return null for empty fields.
*/
class OMB_Profile
{
protected $identifier_uri;
protected $profile_url;
protected $nickname;
protected $license_url;
protected $fullname;
protected $homepage;
protected $bio;
protected $location;
protected $avatar_url;
/** /* The profile as OMB param array. Cached and rebuild on usage.
* Constructor for OMB_Profile false while outdated. */
* protected $param_array;
* Initializes the OMB_Profile object with an identifier uri.
* /**
* @param string $identifier_uri The profile URI as defined by the OMB. A unique * Constructor for OMB_Profile
* and unchanging identifier for a profile. *
* * Initializes the OMB_Profile object with an identifier uri.
* @access public *
*/ * @param string $identifier_uri The profile URI as defined by the OMB;
public function __construct($identifier_uri) { * A unique and never changing identifier for
if (!Validate::uri($identifier_uri)) { * a profile
throw new OMB_InvalidParameterException($identifier_uri, 'profile', *
* @access public
*/
public function __construct($identifier_uri)
{
if (!Validate::uri($identifier_uri)) {
throw new OMB_InvalidParameterException($identifier_uri, 'profile',
'omb_listenee or omb_listener'); 'omb_listenee or omb_listener');
} }
$this->identifier_uri = $identifier_uri; $this->identifier_uri = $identifier_uri;
$this->param_array = false; $this->param_array = false;
}
/**
* Returns the profile as array
*
* The method returns an array which contains the whole profile as array. The
* array is cached and only rebuilt on changes of the profile.
*
* @param bool $force_all Specifies whether empty fields should be added to
* the array as well. This is neccessary to clear
* fields via updateProfile.
*
* @param string $prefix The common prefix to the key for all parameters.
*
* @access public
*
* @return array The profile as parameter array
*/
public function asParameters($prefix, $force_all = false) {
if ($this->param_array === false) {
$this->param_array = array('' => $this->identifier_uri);
if ($force_all || !is_null($this->profile_url)) {
$this->param_array['_profile'] = $this->profile_url;
}
if ($force_all || !is_null($this->homepage)) {
$this->param_array['_homepage'] = $this->homepage;
}
if ($force_all || !is_null($this->nickname)) {
$this->param_array['_nickname'] = $this->nickname;
}
if ($force_all || !is_null($this->license_url)) {
$this->param_array['_license'] = $this->license_url;
}
if ($force_all || !is_null($this->fullname)) {
$this->param_array['_fullname'] = $this->fullname;
}
if ($force_all || !is_null($this->bio)) {
$this->param_array['_bio'] = $this->bio;
}
if ($force_all || !is_null($this->location)) {
$this->param_array['_location'] = $this->location;
}
if ($force_all || !is_null($this->avatar_url)) {
$this->param_array['_avatar'] = $this->avatar_url;
}
}
$ret = array();
foreach ($this->param_array as $k => $v) {
$ret[$prefix . $k] = $v;
}
return $ret;
}
/**
* Builds an OMB_Profile object from array
*
* The method builds an OMB_Profile object from the passed parameters array. The
* array MUST provide a profile URI. The array fields HAVE TO be named according
* to the OMB standard. The prefix (omb_listener or omb_listenee) is passed as a
* parameter.
*
* @param string $parameters An array containing the profile parameters.
* @param string $prefix The common prefix of the profile parameter keys.
*
* @access public
*
* @returns OMB_Profile The built OMB_Profile.
*/
public static function fromParameters($parameters, $prefix) {
if (!isset($parameters[$prefix])) {
throw new OMB_InvalidParameterException('', 'profile', $prefix);
} }
$profile = new OMB_Profile($parameters[$prefix]); /**
$profile->updateFromParameters($parameters, $prefix); * Return the profile as array
return $profile; *
} * Returns an array which contains the whole profile as array.
* The array is cached and only rebuilt on changes of the profile.
*
* @param string $prefix The common prefix to the key for all parameters
* @param bool $force_all Specifies whether empty fields should be added
* to the array as well; This is necessary to
* clear fields via updateProfile
*
* @access public
*
* @return array The profile as parameter array
*/
public function asParameters($prefix, $force_all = false)
{
if ($this->param_array === false) {
$this->param_array = array('' => $this->identifier_uri);
/** if ($force_all || !is_null($this->profile_url)) {
* Update from array $this->param_array['_profile'] = $this->profile_url;
* }
* Updates from the passed parameters array. The array does not have to
* provide a profile URI. The array fields HAVE TO be named according to the if ($force_all || !is_null($this->homepage)) {
* OMB standard. The prefix (omb_listener or omb_listenee) is passed as a $this->param_array['_homepage'] = $this->homepage;
* parameter. }
*
* @param string $parameters An array containing the profile parameters. if ($force_all || !is_null($this->nickname)) {
* @param string $prefix The common prefix of the profile parameter keys. $this->param_array['_nickname'] = $this->nickname;
* }
* @access public
*/ if ($force_all || !is_null($this->license_url)) {
public function updateFromParameters($parameters, $prefix) { $this->param_array['_license'] = $this->license_url;
if (isset($parameters[$prefix.'_profile'])) { }
$this->setProfileURL($parameters[$prefix.'_profile']);
if ($force_all || !is_null($this->fullname)) {
$this->param_array['_fullname'] = $this->fullname;
}
if ($force_all || !is_null($this->bio)) {
$this->param_array['_bio'] = $this->bio;
}
if ($force_all || !is_null($this->location)) {
$this->param_array['_location'] = $this->location;
}
if ($force_all || !is_null($this->avatar_url)) {
$this->param_array['_avatar'] = $this->avatar_url;
}
}
$ret = array();
foreach ($this->param_array as $k => $v) {
$ret[$prefix . $k] = $v;
}
return $ret;
} }
if (isset($parameters[$prefix.'_license'])) { /**
$this->setLicenseURL($parameters[$prefix.'_license']); * Build an OMB_Profile object from array
*
* Builds an OMB_Profile object from the passed parameters array. The
* array MUST provide a profile URI. The array fields HAVE TO be named
* according to the OMB standard. The prefix (omb_listener or omb_listenee)
* is passed as a parameter.
*
* @param string $parameters An array containing the profile parameters
* @param string $prefix The common prefix of the profile parameter keys
*
* @access public
*
* @returns OMB_Profile The built OMB_Profile
*/
public static function fromParameters($parameters, $prefix)
{
if (!isset($parameters[$prefix])) {
throw new OMB_InvalidParameterException('', 'profile', $prefix);
}
$profile = new OMB_Profile($parameters[$prefix]);
$profile->updateFromParameters($parameters, $prefix);
return $profile;
} }
if (isset($parameters[$prefix.'_nickname'])) { /**
$this->setNickname($parameters[$prefix.'_nickname']); * Update from array
*
* Updates from the passed parameters array. The array does not have to
* provide a profile URI. The array fields HAVE TO be named according to the
* OMB standard. The prefix (omb_listener or omb_listenee) is passed as a
* parameter.
*
* @param string $parameters An array containing the profile parameters
* @param string $prefix The common prefix of the profile parameter keys
*
* @access public
*/
public function updateFromParameters($parameters, $prefix)
{
if (isset($parameters[$prefix.'_profile'])) {
$this->setProfileURL($parameters[$prefix.'_profile']);
}
if (isset($parameters[$prefix.'_license'])) {
$this->setLicenseURL($parameters[$prefix.'_license']);
}
if (isset($parameters[$prefix.'_nickname'])) {
$this->setNickname($parameters[$prefix.'_nickname']);
}
if (isset($parameters[$prefix.'_fullname'])) {
$this->setFullname($parameters[$prefix.'_fullname']);
}
if (isset($parameters[$prefix.'_homepage'])) {
$this->setHomepage($parameters[$prefix.'_homepage']);
}
if (isset($parameters[$prefix.'_bio'])) {
$this->setBio($parameters[$prefix.'_bio']);
}
if (isset($parameters[$prefix.'_location'])) {
$this->setLocation($parameters[$prefix.'_location']);
}
if (isset($parameters[$prefix.'_avatar'])) {
$this->setAvatarURL($parameters[$prefix.'_avatar']);
}
} }
if (isset($parameters[$prefix.'_fullname'])) { public function getIdentifierURI()
$this->setFullname($parameters[$prefix.'_fullname']); {
return $this->identifier_uri;
} }
if (isset($parameters[$prefix.'_homepage'])) { public function getProfileURL()
$this->setHomepage($parameters[$prefix.'_homepage']); {
return $this->profile_url;
} }
if (isset($parameters[$prefix.'_bio'])) { public function getHomepage()
$this->setBio($parameters[$prefix.'_bio']); {
return $this->homepage;
} }
if (isset($parameters[$prefix.'_location'])) { public function getNickname()
$this->setLocation($parameters[$prefix.'_location']); {
return $this->nickname;
} }
if (isset($parameters[$prefix.'_avatar'])) { public function getLicenseURL()
$this->setAvatarURL($parameters[$prefix.'_avatar']); {
} return $this->license_url;
}
public function getIdentifierURI() {
return $this->identifier_uri;
}
public function getProfileURL() {
return $this->profile_url;
}
public function getHomepage() {
return $this->homepage;
}
public function getNickname() {
return $this->nickname;
}
public function getLicenseURL() {
return $this->license_url;
}
public function getFullname() {
return $this->fullname;
}
public function getBio() {
return $this->bio;
}
public function getLocation() {
return $this->location;
}
public function getAvatarURL() {
return $this->avatar_url;
}
public function setProfileURL($profile_url) {
if (!OMB_Helper::validateURL($profile_url)) {
throw new OMB_InvalidParameterException($profile_url, 'profile',
'omb_listenee_profile or omb_listener_profile');
}
$this->profile_url = $profile_url;
$this->param_array = false;
}
public function setNickname($nickname) {
if (!Validate::string($nickname,
array('min_length' => 1,
'max_length' => 64,
'format' => VALIDATE_NUM . VALIDATE_ALPHA))) {
throw new OMB_InvalidParameterException($nickname, 'profile', 'nickname');
} }
$this->nickname = $nickname; public function getFullname()
$this->param_array = false; {
} return $this->fullname;
public function setLicenseURL($license_url) {
if (!OMB_Helper::validateURL($license_url)) {
throw new OMB_InvalidParameterException($license_url, 'profile',
'omb_listenee_license or omb_listener_license');
} }
$this->license_url = $license_url;
$this->param_array = false;
}
public function setFullname($fullname) { public function getBio()
if ($fullname === '') { {
$fullname = null; return $this->bio;
} elseif (!Validate::string($fullname, array('max_length' => 255))) {
throw new OMB_InvalidParameterException($fullname, 'profile', 'fullname');
} }
$this->fullname = $fullname;
$this->param_array = false;
}
public function setHomepage($homepage) { public function getLocation()
if ($homepage === '') { {
$homepage = null; return $this->location;
} }
$this->homepage = $homepage;
$this->param_array = false;
}
public function setBio($bio) { public function getAvatarURL()
if ($bio === '') { {
$bio = null; return $this->avatar_url;
} elseif (!Validate::string($bio, array('max_length' => 140))) {
throw new OMB_InvalidParameterException($bio, 'profile', 'fullname');
} }
$this->bio = $bio;
$this->param_array = false;
}
public function setLocation($location) { public function setProfileURL($profile_url)
if ($location === '') { {
$location = null; $this->setVal('profile', $profile_url, 'OMB_Helper::validateURL',
} elseif (!Validate::string($location, array('max_length' => 255))) { 'profile_url');
throw new OMB_InvalidParameterException($location, 'profile', 'fullname');
} }
$this->location = $location;
$this->param_array = false;
}
public function setAvatarURL($avatar_url) { public function setNickname($nickname)
if ($avatar_url === '') { {
$avatar_url = null; $this->setVal('nickname', $nickname, 'OMB_Profile::validateNickname',
} elseif (!OMB_Helper::validateURL($avatar_url)) { 'nickname', true);
throw new OMB_InvalidParameterException($avatar_url, 'profile',
'omb_listenee_avatar or omb_listener_avatar');
} }
$this->avatar_url = $avatar_url;
$this->param_array = false;
}
public function setLicenseURL($license_url)
{
$this->setVal('license', $license_url, 'OMB_Helper::validateURL',
'license_url');
}
public function setFullname($fullname)
{
$this->setVal('fullname', $fullname, 'OMB_Profile::validate255');
}
public function setHomepage($homepage)
{
$this->setVal('homepage', $homepage, 'OMB_Helper::validateURL');
}
public function setBio($bio)
{
$this->setVal('bio', $bio, 'OMB_Profile::validate140');
}
public function setLocation($location)
{
$this->setVal('location', $location, 'OMB_Profile::validate255');
}
public function setAvatarURL($avatar_url)
{
$this->setVal('avatar', $avatar_url, 'OMB_Helper::validateURL',
'avatar_url');
}
protected static function validate255($str)
{
return Validate::string($str, array('max_length' => 255));
}
protected static function validate140($str)
{
return Validate::string($str, array('max_length' => 140));
}
protected static function validateNickname($str)
{
return Validate::string($str,
array('min_length' => 1,
'max_length' => 64,
'format' => VALIDATE_NUM . VALIDATE_ALPHA));
}
/**
* Set a value
*
* Updates a value specified by a parameter name and the new value.
*
* @param string $param The parameter name according to OMB
* @param string $value The new value
* @param callback $validator A validator function for the parameter
* @param string $field The name of the field in OMB_Profile
* @param bool $force Whether null values should be checked as well
*/
protected function setVal($param, $value, $validator, $field = null,
$force = false)
{
if (is_null($field)) {
$field = $param;
}
if ($value === '' && !$force) {
$value = null;
} elseif (!call_user_func($validator, $value)) {
throw new OMB_InvalidParameterException($value, 'profile', $param);
}
if ($this->$field !== $value) {
$this->$field = $value;
$this->param_array = false;
}
}
} }
?> ?>

View File

@ -1,9 +1,6 @@
<?php <?php
/** /**
* Exception stating that the remote service had a failure * This file is part of libomb
*
* This exception is raised when a remote service failed to return a valid
* response to a request or send a valid request.
* *
* PHP version 5 * PHP version 5
* *
@ -20,23 +17,57 @@
* You should have received a copy of the GNU Affero General Public License * 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/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
* @package OMB * @package OMB
* @author Adrian Lang <mail@adrianlang.de> * @author Adrian Lang <mail@adrianlang.de>
* @copyright 2009 Adrian Lang * @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
* @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0 * @version 0.1a-20090828
**/ * @link http://adrianlang.de/libomb
class OMB_RemoteServiceException extends Exception { */
public static function fromYadis($request_uri, $result) {
if ($result->status == 200) {
$err = 'Got wrong response ' . $result->body;
} else {
$err = 'Got error code ' . $result->status . ' with response ' . $result->body;
}
return new OMB_RemoteServiceException($request_uri . ': ' . $err);
}
public static function forRequest($action_uri, $failure) { /**
return new OMB_RemoteServiceException("Handler for $action_uri: " . $failure); * Exception stating that the remote service had a failure
} *
* This exception is raised when a remote service failed to return a valid
* response to a request or send a valid request.
*/
class OMB_RemoteServiceException extends Exception
{
/**
* Create exception from Yadis response
*
* Creates an exception from a passed yadis result.
*
* @param string $request_uri The target URI for the failed
* request
* @param Auth_Yadis_HTTPResponse $result The result of the failed
* request
*
* @return OMB_RemoteServiceException A new exception
*/
public static function fromYadis($request_uri, $result)
{
if ($result->status == 200) {
$err = 'Got wrong response ' . $result->body;
} else {
$err = 'Got error code ' . $result->status . ' with response ' .
$result->body;
}
return OMB_RemoteServiceException::forRequest($request_uri, $err);
}
/**
* Create exception for a call to a resource
*
* Creates an exception for a given error message and target URI.
*
* @param string $action_uri The target URI for the failed request
* @param string $failure An error message
*
* @return OMB_RemoteServiceException A new exception
*/
public static function forRequest($action_uri, $failure)
{
return new OMB_RemoteServiceException("Handler for $action_uri: $failure");
}
} }
?> ?>

View File

@ -1,19 +1,6 @@
<?php <?php
require_once 'constants.php';
require_once 'Validate.php';
require_once 'Auth/Yadis/Yadis.php';
require_once 'OAuth.php';
require_once 'unsupportedserviceexception.php';
require_once 'remoteserviceexception.php';
require_once 'omb_yadis_xrds.php';
require_once 'helper.php';
/** /**
* OMB service representation * This file is part of libomb
*
* This class represents a complete remote OMB service. It provides discovery
* and execution of the services methods.
* *
* PHP version 5 * PHP version 5
* *
@ -30,401 +17,445 @@ require_once 'helper.php';
* You should have received a copy of the GNU Affero General Public License * 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/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
* @package OMB * @package OMB
* @author Adrian Lang <mail@adrianlang.de> * @author Adrian Lang <mail@adrianlang.de>
* @copyright 2009 Adrian Lang * @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
* @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0 * @version 0.1a-20090828
**/ * @link http://adrianlang.de/libomb
*/
class OMB_Service_Consumer { require_once 'Validate.php';
protected $url; /* The service URL */ require_once 'Auth/Yadis/Yadis.php';
protected $services; /* An array of strings mapping service URI to require_once 'OAuth.php';
service URL */ require_once 'constants.php';
require_once 'helper.php';
require_once 'omb_yadis_xrds.php';
require_once 'profile.php';
require_once 'remoteserviceexception.php';
require_once 'unsupportedserviceexception.php';
protected $token; /* An OAuthToken */ /**
* OMB service representation
*
* This class represents a complete remote OMB service. It provides discovery
* and execution of the services methods.
*/
class OMB_Service_Consumer
{
protected $url; /* The service URL */
protected $services; /* An array of strings mapping service URI to
service URL */
protected $listener_uri; /* The URI identifying the listener, i. e. the protected $token; /* An OAuthToken */
remote user. */
protected $listenee_uri; /* The URI identifying the listenee, i. e. the protected $listener_uri; /* The URI identifying the listener, i. e. the
local user during an auth request. */ remote user. */
/** protected $listenee_uri; /* The URI identifying the listenee, i. e. the
* According to OAuth Core 1.0, an user authorization request is no full-blown local user during an auth request. */
* OAuth request. nonce, timestamp, consumer_key and signature are not needed
* in this step. See http://laconi.ca/trac/ticket/827 for more informations.
*
* Since Laconica up to version 0.7.2 performs a full OAuth request check, a
* correct request would fail.
**/
public $performLegacyAuthRequest = true;
/* Helper stuff we are going to need. */ /**
protected $fetcher; * According to OAuth Core 1.0, an user authorization request is no
protected $oauth_consumer; * full-blown OAuth request. nonce, timestamp, consumer_key and signature
protected $datastore; * are not needed in this step. See http://laconi.ca/trac/ticket/827 for
* more informations.
*
* Since Laconica up to version 0.7.2 performs a full OAuth request check, a
* correct request would fail.
*/
public $performLegacyAuthRequest = true;
/** /* Helper stuff we are going to need. */
* Constructor for OMB_Service_Consumer protected $fetcher;
* protected $oauth_consumer;
* Initializes an OMB_Service_Consumer object representing the OMB service protected $datastore;
* specified by $service_url. Performs a complete service discovery using
* Yadis.
* Throws OMB_UnsupportedServiceException if XRDS file does not specify a
* complete OMB service.
*
* @param string $service_url The URL of the service
* @param string $consumer_url An URL representing the consumer
* @param OMB_Datastore $datastore An instance of a class implementing
* OMB_Datastore
*
* @access public
**/
public function __construct ($service_url, $consumer_url, $datastore) {
$this->url = $service_url;
$this->fetcher = Auth_Yadis_Yadis::getHTTPFetcher();
$this->datastore = $datastore;
$this->oauth_consumer = new OAuthConsumer($consumer_url, '');
$xrds = OMB_Yadis_XRDS::fromYadisURL($service_url, $this->fetcher); /**
* Constructor for OMB_Service_Consumer
*
* Initializes an OMB_Service_Consumer object representing the OMB service
* specified by $service_url. Performs a complete service discovery using
* Yadis.
* Throws OMB_UnsupportedServiceException if XRDS file does not specify a
* complete OMB service.
*
* @param string $service_url The URL of the service
* @param string $consumer_url An URL representing the consumer
* @param OMB_Datastore $datastore An instance of a class implementing
* OMB_Datastore
*
* @access public
*/
public function __construct ($service_url, $consumer_url, $datastore)
{
$this->url = $service_url;
$this->fetcher = Auth_Yadis_Yadis::getHTTPFetcher();
$this->datastore = $datastore;
$this->oauth_consumer = new OAuthConsumer($consumer_url, '');
/* Detect our services. This performs a validation as well, since $xrds = OMB_Yadis_XRDS::fromYadisURL($service_url, $this->fetcher);
getService und getXRD throw exceptions on failure. */
$this->services = array();
foreach (array(OAUTH_DISCOVERY => OMB_Helper::$OAUTH_SERVICES, /* Detect our services. This performs a validation as well, since
OMB_VERSION => OMB_Helper::$OMB_SERVICES) getService und getXRD throw exceptions on failure. */
as $service_root => $targetservices) { $this->services = array();
$uris = $xrds->getService($service_root)->getURIs();
$xrd = $xrds->getXRD($uris[0]); foreach (array(OAUTH_DISCOVERY => OMB_Helper::$OAUTH_SERVICES,
foreach ($targetservices as $targetservice) { OMB_VERSION => OMB_Helper::$OMB_SERVICES)
$yadis_service = $xrd->getService($targetservice); as $service_root => $targetservices) {
if ($targetservice == OAUTH_ENDPOINT_REQUEST) { $uris = $xrds->getService($service_root)->getURIs();
$localid = $yadis_service->getElements('xrd:LocalID'); $xrd = $xrds->getXRD($uris[0]);
$this->listener_uri = $yadis_service->parser->content($localid[0]); foreach ($targetservices as $targetservice) {
$yadis_service = $xrd->getService($targetservice);
if ($targetservice == OAUTH_ENDPOINT_REQUEST) {
$localid =
$yadis_service->getElements('xrd:LocalID');
$this->listener_uri =
$yadis_service->parser->content($localid[0]);
}
$uris = $yadis_service->getURIs();
$this->services[$targetservice] = $uris[0];
}
} }
$uris = $yadis_service->getURIs();
$this->services[$targetservice] = $uris[0];
}
}
}
/**
* Get the handler URI for a service
*
* Returns the URI the remote web service has specified for the given
* service.
*
* @param string $service The URI identifying the service
*
* @access public
*
* @return string The service handler URI
**/
public function getServiceURI($service) {
return $this->services[$service];
}
/**
* Get the remote users URI
*
* Returns the URI of the remote user, i. e. the listener.
*
* @access public
*
* @return string The remote users URI
**/
public function getRemoteUserURI() {
return $this->listener_uri;
}
/**
* Get the listenees URI
*
* Returns the URI of the user being subscribed to, i. e. the local user.
*
* @access public
*
* @return string The local users URI
**/
public function getListeneeURI() {
return $this->listenee_uri;
}
/**
* Request a request token
*
* Performs a token request on the service. Returns an OAuthToken on success.
* Throws an exception if the request fails.
*
* @access public
*
* @return OAuthToken An unauthorized request token
**/
public function requestToken() {
/* Set the token to null just in case the user called setToken. */
$this->token = null;
$result = $this->performAction(OAUTH_ENDPOINT_REQUEST,
array('omb_listener' => $this->listener_uri));
if ($result->status != 200) {
throw OMB_RemoteServiceException::fromYadis(OAUTH_ENDPOINT_REQUEST,
$result);
}
parse_str($result->body, $return);
if (!isset($return['oauth_token']) || !isset($return['oauth_token_secret'])) {
throw OMB_RemoteServiceException::fromYadis(OAUTH_ENDPOINT_REQUEST,
$result);
}
$this->setToken($return['oauth_token'], $return['oauth_token_secret']);
return $this->token;
}
/**
*
* Request authorization
*
* Returns an URL which equals to an authorization request. The end user
* should be redirected to this location to perform authorization.
* The $finish_url should be a local resource which invokes
* OMB_Consumer::finishAuthorization on request.
*
* @param OMB_Profile $profile An OMB_Profile object representing the
* soon-to-be subscribed (i. e. local) user
* @param string $finish_url Target location after successful
* authorization
*
* @access public
*
* @return string An URL representing an authorization request
**/
public function requestAuthorization($profile, $finish_url) {
if ($this->performLegacyAuthRequest) {
$params = $profile->asParameters('omb_listenee', false);
$params['omb_listener'] = $this->listener_uri;
$params['oauth_callback'] = $finish_url;
$url = $this->prepareAction(OAUTH_ENDPOINT_AUTHORIZE, $params, 'GET')->to_url();
} else {
$params = array(
'oauth_callback' => $finish_url,
'oauth_token' => $this->token->key,
'omb_version' => OMB_VERSION,
'omb_listener' => $this->listener_uri);
$params = array_merge($profile->asParameters('omb_listenee', false). $params);
/* Build result URL. */
$url = $this->services[OAUTH_ENDPOINT_AUTHORIZE];
$url .= (strrpos($url, '?') === false ? '?' : '&');
foreach ($params as $k => $v) {
$url .= OAuthUtil::urlencode_rfc3986($k) . '=' . OAuthUtil::urlencode_rfc3986($v) . '&';
}
} }
$this->listenee_uri = $profile->getIdentifierURI(); /**
* Get the handler URI for a service
return $url; *
} * Returns the URI the remote web service has specified for the given
* service.
/** *
* Finish authorization * @param string $service The URI identifying the service
* *
* Finish the subscription process by converting the received and authorized * @access public
* request token into an access token. After that, the subscribers profile *
* and the subscription are stored in the database. * @return string The service handler URI
* Expects an OAuthRequest in query parameters. */
* Throws exceptions on failure. public function getServiceURI($service)
* {
* @access public return $this->services[$service];
**/
public function finishAuthorization() {
OMB_Helper::removeMagicQuotesFromRequest();
$req = OAuthRequest::from_request();
if ($req->get_parameter('oauth_token') !=
$this->token->key) {
/* Thats not the token I wanted to get authorized. */
throw new OAuthException('The authorized token does not equal the ' .
'submitted token.');
} }
if ($req->get_parameter('omb_version') != OMB_VERSION) { /**
throw new OMB_RemoteServiceException('The remote service uses an ' . * Get the remote users URI
'unsupported OMB version'); *
* Returns the URI of the remote user, i. e. the listener.
*
* @access public
*
* @return string The remote users URI
*/
public function getRemoteUserURI()
{
return $this->listener_uri;
} }
/* Construct the profile to validate it. */ /**
* Get the listenees URI
/* Fix OMB bug. Listener URI is not passed. */ *
if ($_SERVER['REQUEST_METHOD'] == 'POST') { * Returns the URI of the user being subscribed to, i. e. the local user.
$params = $_POST; *
} else { * @access public
$params = $_GET; *
} * @return string The local users URI
$params['omb_listener'] = $this->listener_uri; */
public function getListeneeURI()
require_once 'profile.php'; {
$listener = OMB_Profile::fromParameters($params, 'omb_listener'); return $this->listenee_uri;
/* Ask the remote service to convert the authorized request token into an
access token. */
$result = $this->performAction(OAUTH_ENDPOINT_ACCESS, array());
if ($result->status != 200) {
throw new OAuthException('Could not get access token');
} }
parse_str($result->body, $return); /**
if (!isset($return['oauth_token']) || !isset($return['oauth_token_secret'])) { * Request a request token
throw new OAuthException('Could not get access token'); *
* Performs a token request on the service. Returns an OAuthToken on success.
* Throws an exception if the request fails.
*
* @access public
*
* @return OAuthToken An unauthorized request token
*/
public function requestToken()
{
/* Set the token to null just in case the user called setToken. */
$this->token = null;
$result = $this->performAction(OAUTH_ENDPOINT_REQUEST,
array('omb_listener' => $this->listener_uri));
if ($result->status != 200) {
throw OMB_RemoteServiceException::fromYadis(OAUTH_ENDPOINT_REQUEST,
$result);
}
parse_str($result->body, $return);
if (!isset($return['oauth_token']) ||
!isset($return['oauth_token_secret'])) {
throw OMB_RemoteServiceException::fromYadis(OAUTH_ENDPOINT_REQUEST,
$result);
}
$this->setToken($return['oauth_token'], $return['oauth_token_secret']);
return $this->token;
} }
$this->setToken($return['oauth_token'], $return['oauth_token_secret']);
/* Subscription is finished and valid. Now store the new subscriber and the /**
subscription in the database. */ * Request authorization
*
* Returns an URL which equals to an authorization request. The end user
* should be redirected to this location to perform authorization.
* The $finish_url should be a local resource which invokes
* OMB_Consumer::finishAuthorization on request.
*
* @param OMB_Profile $profile An OMB_Profile object representing the
* soon-to-be subscribed (i. e. local) user
* @param string $finish_url Target location after successful
* authorization
*
* @access public
*
* @return string An URL representing an authorization request
*/
public function requestAuthorization($profile, $finish_url)
{
if ($this->performLegacyAuthRequest) {
$params = $profile->asParameters('omb_listenee',
false);
$params['omb_listener'] = $this->listener_uri;
$params['oauth_callback'] = $finish_url;
$this->datastore->saveProfile($listener); $url = $this->prepareAction(OAUTH_ENDPOINT_AUTHORIZE, $params,
$this->datastore->saveSubscription($this->listener_uri, 'GET')->to_url();
$this->listenee_uri, } else {
$this->token); $params = array('oauth_callback' => $finish_url,
} 'oauth_token' => $this->token->key,
'omb_version' => OMB_VERSION,
'omb_listener' => $this->listener_uri);
/** $params = array_merge($profile->asParameters('omb_listenee', false),
* Return the URI identifying the listener $params);
*
* Returns the URI for the OMB user who tries to subscribe or already has
* subscribed our user. This method is a workaround for a serious OMB flaw:
* The Listener URI is not passed in the finishauthorization call.
*
* @access public
*
* @return string the listeners URI
**/
public function getListenerURI() {
return $this->listener_uri;
}
/** /* Build result URL. */
* Inform the service about a profile update $url = $this->services[OAUTH_ENDPOINT_AUTHORIZE] .
* (strrpos($url, '?') === false ? '?' : '&');
* Sends an updated profile to the service. foreach ($params as $k => $v) {
* $url .= OAuthUtil::urlencode_rfc3986($k) . '=' .
* @param OMB_Profile $profile The profile that has changed OAuthUtil::urlencode_rfc3986($v) . '&';
* }
* @access public }
**/
public function updateProfile($profile) {
$params = $profile->asParameters('omb_listenee', true);
$this->performOMBAction(OMB_ENDPOINT_UPDATEPROFILE, $params, $profile->getIdentifierURI());
}
/** $this->listenee_uri = $profile->getIdentifierURI();
* Inform the service about a new notice
*
* Sends a notice to the service.
*
* @param OMB_Notice $notice The notice
*
* @access public
**/
public function postNotice($notice) {
$params = $notice->asParameters();
$params['omb_listenee'] = $notice->getAuthor()->getIdentifierURI();
$this->performOMBAction(OMB_ENDPOINT_POSTNOTICE, $params, $params['omb_listenee']);
}
/** return $url;
* Set the token member variable }
*
* Initializes the token based on given token and secret token. /**
* * Finish authorization
* @param string $token The token *
* @param string $secret The secret token * Finish the subscription process by converting the received and authorized
* * request token into an access token. After that, the subscribers profile
* @access public * and the subscription are stored in the database.
**/ * Expects an OAuthRequest in query parameters.
public function setToken($token, $secret) { * Throws exceptions on failure.
$this->token = new OAuthToken($token, $secret); *
} * @access public
*/
/** public function finishAuthorization()
* Prepare an OAuthRequest object {
* OMB_Helper::removeMagicQuotesFromRequest();
* Creates an OAuthRequest object mapping the request specified by the $req = OAuthRequest::from_request();
* parameters. if ($req->get_parameter('oauth_token') != $this->token->key) {
* /* Thats not the token I wanted to get authorized. */
* @param string $action_uri The URI specifying the target service throw new OAuthException('The authorized token does not equal ' .
* @param array $params Additional parameters for the service call 'the submitted token.');
* @param string $method The HTTP method used to call the service }
* ('POST' or 'GET', usually)
* if ($req->get_parameter('omb_version') != OMB_VERSION) {
* @access protected throw new OMB_RemoteServiceException('The remote service uses an ' .
* 'unsupported OMB version');
* @return OAuthRequest the prepared request }
**/
protected function prepareAction($action_uri, $params, $method) { /* Construct the profile to validate it. */
$url = $this->services[$action_uri];
/* Fix OMB bug. Listener URI is not passed. */
$url_params = array(); if ($_SERVER['REQUEST_METHOD'] == 'POST') {
parse_str(parse_url($url, PHP_URL_QUERY), $url_params); $params = $_POST;
} else {
/* Add OMB version. */ $params = $_GET;
$url_params['omb_version'] = OMB_VERSION; }
$params['omb_listener'] = $this->listener_uri;
/* Add user-defined parameters. */
$url_params = array_merge($url_params, $params); $listener = OMB_Profile::fromParameters($params, 'omb_listener');
$req = OAuthRequest::from_consumer_and_token($this->oauth_consumer, /* Ask the remote service to convert the authorized request token into
$this->token, $method, $url, $url_params); an access token. */
/* Sign the request. */ $result = $this->performAction(OAUTH_ENDPOINT_ACCESS, array());
$req->sign_request(new OAuthSignatureMethod_HMAC_SHA1(), if ($result->status != 200) {
$this->oauth_consumer, $this->token); throw new OAuthException('Could not get access token');
}
return $req;
} parse_str($result->body, $return);
if (!isset($return['oauth_token']) ||
/** !isset($return['oauth_token_secret'])) {
* Perform a service call throw new OAuthException('Could not get access token');
* }
* Creates an OAuthRequest object and execute the mapped call as POST request. $this->setToken($return['oauth_token'], $return['oauth_token_secret']);
*
* @param string $action_uri The URI specifying the target service /* Subscription is finished and valid. Now store the new subscriber and
* @param array $params Additional parameters for the service call the subscription in the database. */
*
* @access protected $this->datastore->saveProfile($listener);
* $this->datastore->saveSubscription($this->listener_uri,
* @return Auth_Yadis_HTTPResponse The POST request response $this->listenee_uri,
**/ $this->token);
protected function performAction($action_uri, $params) { }
$req = $this->prepareAction($action_uri, $params, 'POST');
/**
/* Return result page. */ * Return the URI identifying the listener
return $this->fetcher->post($req->get_normalized_http_url(), $req->to_postdata(), array()); *
} * Returns the URI for the OMB user who tries to subscribe or already has
* subscribed our user. This method is a workaround for a serious OMB flaw:
/** * The Listener URI is not passed in the finishauthorization call.
* Perform an OMB action *
* * @access public
* Executes an OMB action to date, its one of updateProfile or postNotice. *
* * @return string the listeners URI
* @param string $action_uri The URI specifying the target service */
* @param array $params Additional parameters for the service call public function getListenerURI()
* @param string $listenee_uri The URI identifying the local user for whom {
* the action is performed return $this->listener_uri;
* }
* @access protected
**/ /**
protected function performOMBAction($action_uri, $params, $listenee_uri) { * Inform the service about a profile update
$result = $this->performAction($action_uri, $params); *
if ($result->status == 403) { * Sends an updated profile to the service.
/* The remote user unsubscribed us. */ *
$this->datastore->deleteSubscription($this->listener_uri, $listenee_uri); * @param OMB_Profile $profile The profile that has changed
} else if ($result->status != 200 || *
strpos($result->body, 'omb_version=' . OMB_VERSION) === false) { * @access public
/* The server signaled an error or sent an incorrect response. */ */
throw OMB_RemoteServiceException::fromYadis($action_uri, $result); public function updateProfile($profile)
{
$params = $profile->asParameters('omb_listenee', true);
$this->performOMBAction(OMB_ENDPOINT_UPDATEPROFILE, $params,
$profile->getIdentifierURI());
}
/**
* Inform the service about a new notice
*
* Sends a notice to the service.
*
* @param OMB_Notice $notice The notice
*
* @access public
*/
public function postNotice($notice)
{
$params = $notice->asParameters();
$params['omb_listenee'] = $notice->getAuthor()->getIdentifierURI();
$this->performOMBAction(OMB_ENDPOINT_POSTNOTICE, $params,
$params['omb_listenee']);
}
/**
* Set the token member variable
*
* Initializes the token based on given token and secret token.
*
* @param string $token The token
* @param string $secret The secret token
*
* @access public
*/
public function setToken($token, $secret)
{
$this->token = new OAuthToken($token, $secret);
}
/**
* Prepare an OAuthRequest object
*
* Creates an OAuthRequest object mapping the request specified by the
* parameters.
*
* @param string $action_uri The URI specifying the target service
* @param array $params Additional parameters for the service call
* @param string $method The HTTP method used to call the service
* ('POST' or 'GET', usually)
*
* @access protected
*
* @return OAuthRequest the prepared request
*/
protected function prepareAction($action_uri, $params, $method)
{
$url = $this->services[$action_uri];
$url_params = array();
parse_str(parse_url($url, PHP_URL_QUERY), $url_params);
/* Add OMB version. */
$url_params['omb_version'] = OMB_VERSION;
/* Add user-defined parameters. */
$url_params = array_merge($url_params, $params);
$req = OAuthRequest::from_consumer_and_token($this->oauth_consumer,
$this->token, $method,
$url, $url_params);
/* Sign the request. */
$req->sign_request(new OAuthSignatureMethod_HMAC_SHA1(),
$this->oauth_consumer, $this->token);
return $req;
}
/**
* Perform a service call
*
* Creates an OAuthRequest object and execute the mapped call as POST
* request.
*
* @param string $action_uri The URI specifying the target service
* @param array $params Additional parameters for the service call
*
* @access protected
*
* @return Auth_Yadis_HTTPResponse The POST request response
*/
protected function performAction($action_uri, $params)
{
$req = $this->prepareAction($action_uri, $params, 'POST');
/* Return result page. */
return $this->fetcher->post($req->get_normalized_http_url(),
$req->to_postdata(), array());
}
/**
* Perform an OMB action
*
* Executes an OMB action as of OMB 0.1, its one of updateProfile and
* postNotice.
*
* @param string $action_uri The URI specifying the target service
* @param array $params Additional parameters for the service call
* @param string $listenee_uri The URI identifying the local user for whom
* the action is performed
*
* @access protected
*/
protected function performOMBAction($action_uri, $params, $listenee_uri)
{
$result = $this->performAction($action_uri, $params);
if ($result->status == 403) {
/* The remote user unsubscribed us. */
$this->datastore->deleteSubscription($this->listener_uri,
$listenee_uri);
} else if ($result->status != 200 ||
strpos($result->body, 'omb_version=' . OMB_VERSION) === false) {
/* The server signaled an error or sent an incorrect response. */
throw OMB_RemoteServiceException::fromYadis($action_uri, $result);
}
} }
}
} }
?>

View File

@ -1,13 +1,6 @@
<?php <?php
require_once 'constants.php';
require_once 'remoteserviceexception.php';
require_once 'helper.php';
/** /**
* OMB service realization * This file is part of libomb
*
* This class realizes a complete, simple OMB service.
* *
* PHP version 5 * PHP version 5
* *
@ -24,406 +17,445 @@ require_once 'helper.php';
* You should have received a copy of the GNU Affero General Public License * 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/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
* @package OMB * @package OMB
* @author Adrian Lang <mail@adrianlang.de> * @author Adrian Lang <mail@adrianlang.de>
* @copyright 2009 Adrian Lang * @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
* @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0 * @version 0.1a-20090828
**/ * @link http://adrianlang.de/libomb
*/
class OMB_Service_Provider { require_once 'constants.php';
protected $user; /* An OMB_Profile representing the user */ require_once 'helper.php';
protected $datastore; /* AN OMB_Datastore */ require_once 'notice.php';
require_once 'remoteserviceexception.php';
protected $remote_user; /* An OMB_Profile representing the remote user during /**
the authorization process */ * OMB service realization
*
* This class realizes a complete, simple OMB service.
*/
class OMB_Service_Provider
{
protected $user; /* An OMB_Profile representing the user */
protected $datastore; /* AN OMB_Datastore */
protected $oauth_server; /* An OAuthServer; should only be accessed via protected $remote_user; /* An OMB_Profile representing the remote user
getOAuthServer. */ during the authorization process */
/** protected $oauth_server; /* An OAuthServer; should only be accessed via
* Initialize an OMB_Service_Provider object getOAuthServer. */
*
* Constructs an OMB_Service_Provider instance that provides OMB services
* referring to a particular user.
*
* @param OMB_Profile $user An OMB_Profile; mandatory for XRDS
* output, user auth handling and OMB
* action performing
* @param OMB_Datastore $datastore An OMB_Datastore; mandatory for
* everything but XRDS output
* @param OAuthServer $oauth_server An OAuthServer; used for token writing
* and OMB action handling; will use
* default value if not set
*
* @access public
**/
public function __construct ($user = null, $datastore = null, $oauth_server = null) {
$this->user = $user;
$this->datastore = $datastore;
$this->oauth_server = $oauth_server;
}
public function getRemoteUser() { /**
return $this->remote_user; * Initialize an OMB_Service_Provider object
} *
* Constructs an OMB_Service_Provider instance that provides OMB services
/** * referring to a particular user.
* Write a XRDS document *
* * @param OMB_Profile $user An OMB_Profile; mandatory for XRDS
* Writes a XRDS document specifying the OMB service. Optionally uses a * output, user auth handling and OMB
* given object of a class implementing OMB_XRDS_Writer for output. Else * action performing
* OMB_Plain_XRDS_Writer is used. * @param OMB_Datastore $datastore An OMB_Datastore; mandatory for
* * everything but XRDS output
* @param OMB_XRDS_Mapper $xrds_mapper An object mapping actions to URLs * @param OAuthServer $oauth_server An OAuthServer; used for token writing
* @param OMB_XRDS_Writer $xrds_writer Optional; The OMB_XRDS_Writer used to * and OMB action handling; will use
* write the XRDS document * default value if not set
* *
* @access public * @access public
* */
* @return mixed Depends on the used OMB_XRDS_Writer; OMB_Plain_XRDS_Writer public function __construct ($user = null, $datastore = null,
* returns nothing. $oauth_server = null)
**/ {
public function writeXRDS($xrds_mapper, $xrds_writer = null) { $this->user = $user;
if ($xrds_writer == null) { $this->datastore = $datastore;
require_once 'plain_xrds_writer.php'; $this->oauth_server = $oauth_server;
$xrds_writer = new OMB_Plain_XRDS_Writer();
}
return $xrds_writer->writeXRDS($this->user, $xrds_mapper);
}
/**
* Echo a request token
*
* Outputs an unauthorized request token for the query found in $_GET or
* $_POST.
*
* @access public
**/
public function writeRequestToken() {
OMB_Helper::removeMagicQuotesFromRequest();
echo $this->getOAuthServer()->fetch_request_token(OAuthRequest::from_request());
}
/**
* Handle an user authorization request.
*
* Parses an authorization request. This includes OAuth and OMB verification.
* Throws exceptions on failures. Returns an OMB_Profile object representing
* the remote user.
*
* The OMB_Profile passed to the constructor of OMB_Service_Provider should
* not represent the user specified in the authorization request, but the one
* currently logged in to the service. This condition being satisfied,
* handleUserAuth will check whether the listener specified in the request is
* identical to the logged in user.
*
* @access public
*
* @return OMB_Profile The profile of the soon-to-be subscribed, i. e. remote
* user
**/
public function handleUserAuth() {
OMB_Helper::removeMagicQuotesFromRequest();
/* Verify the request token. */
$this->token = $this->datastore->lookup_token(null, "request", $_GET['oauth_token']);
if (is_null($this->token)) {
throw new OAuthException('The given request token has not been issued ' .
'by this service.');
} }
/* Verify the OMB part. */ /**
* Return the remote user during user authorization
if ($_GET['omb_version'] !== OMB_VERSION) { *
throw OMB_RemoteServiceException::forRequest(OAUTH_ENDPOINT_AUTHORIZE, * Returns an OMB_Profile representing the remote user during the user
'Wrong OMB version ' . $_GET['omb_version']); * authorization request.
*
* @return OMB_Profile The remote user
*/
public function getRemoteUser()
{
return $this->remote_user;
} }
if ($_GET['omb_listener'] !== $this->user->getIdentifierURI()) { /**
throw OMB_RemoteServiceException::forRequest(OAUTH_ENDPOINT_AUTHORIZE, * Write a XRDS document
'Wrong OMB listener ' . $_GET['omb_listener']); *
} * Writes a XRDS document specifying the OMB service. Optionally uses a
* given object of a class implementing OMB_XRDS_Writer for output. Else
foreach (array('omb_listenee', 'omb_listenee_profile', * OMB_Plain_XRDS_Writer is used.
'omb_listenee_nickname', 'omb_listenee_license') as $param) { *
if (!isset($_GET[$param]) || is_null($_GET[$param])) { * @param OMB_XRDS_Mapper $xrds_mapper An object mapping actions to URLs
throw OMB_RemoteServiceException::forRequest(OAUTH_ENDPOINT_AUTHORIZE, * @param OMB_XRDS_Writer $xrds_writer Optional; The OMB_XRDS_Writer used to
"Required parameter '$param' not found"); * write the XRDS document
} *
} * @access public
*
/* Store given callback for later use. */ * @return mixed Depends on the used OMB_XRDS_Writer; OMB_Plain_XRDS_Writer
if (isset($_GET['oauth_callback']) && $_GET['oauth_callback'] !== '') { * returns nothing.
$this->callback = $_GET['oauth_callback']; */
if (!OMB_Helper::validateURL($this->callback)) { public function writeXRDS($xrds_mapper, $xrds_writer = null)
throw OMB_RemoteServiceException::forRequest(OAUTH_ENDPOINT_AUTHORIZE, {
'Invalid callback URL specified'); if ($xrds_writer == null) {
} require_once 'plain_xrds_writer.php';
} $xrds_writer = new OMB_Plain_XRDS_Writer();
$this->remote_user = OMB_Profile::fromParameters($_GET, 'omb_listenee');
return $this->remote_user;
}
/**
* Continue the OAuth dance after user authorization
*
* Performs the appropriate actions after user answered the authorization
* request.
*
* @param bool $accepted Whether the user granted authorization
*
* @access public
*
* @return array A two-component array with the values:
* - callback The callback URL or null if none given
* - token The authorized request token or null if not
* authorized.
**/
public function continueUserAuth($accepted) {
$callback = $this->callback;
if (!$accepted) {
$this->datastore->revoke_token($this->token->key);
$this->token = null;
/* TODO: The handling is probably wrong in terms of OAuth 1.0 but the way
laconica works. Moreover I dont know the right way either. */
} else {
$this->datastore->authorize_token($this->token->key);
$this->datastore->saveProfile($this->remote_user);
$this->datastore->saveSubscription($this->user->getIdentifierURI(),
$this->remote_user->getIdentifierURI(), $this->token);
if (!is_null($this->callback)) {
/* Callback wants to get some informations as well. */
$params = $this->user->asParameters('omb_listener', false);
$params['oauth_token'] = $this->token->key;
$params['omb_version'] = OMB_VERSION;
$callback .= (parse_url($this->callback, PHP_URL_QUERY) ? '&' : '?');
foreach ($params as $k => $v) {
$callback .= OAuthUtil::urlencode_rfc3986($k) . '=' .
OAuthUtil::urlencode_rfc3986($v) . '&';
} }
} return $xrds_writer->writeXRDS($this->user, $xrds_mapper);
} }
return array($callback, $this->token);
}
/** /**
* Echo an access token * Echo a request token
* *
* Outputs an access token for the query found in $_POST. OMB 0.1 specifies * Outputs an unauthorized request token for the query found in $_GET or
* that the access token request has to be a POST even if OAuth allows GET as * $_POST.
* well. *
* * @access public
* @access public */
**/ public function writeRequestToken()
public function writeAccessToken() { {
OMB_Helper::removeMagicQuotesFromRequest(); OMB_Helper::removeMagicQuotesFromRequest();
echo $this->getOAuthServer()->fetch_access_token( echo $this->getOAuthServer()->fetch_request_token(
OAuthRequest::from_request());
}
/**
* Handle an user authorization request.
*
* Parses an authorization request. This includes OAuth and OMB
* verification.
* Throws exceptions on failures. Returns an OMB_Profile object representing
* the remote user.
*
* The OMB_Profile passed to the constructor of OMB_Service_Provider should
* not represent the user specified in the authorization request, but the
* one currently logged in to the service. This condition being satisfied,
* handleUserAuth will check whether the listener specified in the request
* is identical to the logged in user.
*
* @access public
*
* @return OMB_Profile The profile of the soon-to-be subscribed, i. e.
* remote user
*/
public function handleUserAuth()
{
OMB_Helper::removeMagicQuotesFromRequest();
/* Verify the request token. */
$this->token = $this->datastore->lookup_token(null, "request",
$_GET['oauth_token']);
if (is_null($this->token)) {
throw new OAuthException('The given request token has not been ' .
'issued by this service.');
}
/* Verify the OMB part. */
if ($_GET['omb_version'] !== OMB_VERSION) {
throw OMB_RemoteServiceException::forRequest(OAUTH_ENDPOINT_AUTHORIZE,
'Wrong OMB version ' .
$_GET['omb_version']);
}
if ($_GET['omb_listener'] !== $this->user->getIdentifierURI()) {
throw OMB_RemoteServiceException::forRequest(OAUTH_ENDPOINT_AUTHORIZE,
'Wrong OMB listener ' .
$_GET['omb_listener']);
}
foreach (array('omb_listenee', 'omb_listenee_profile',
'omb_listenee_nickname', 'omb_listenee_license') as $param) {
if (!isset($_GET[$param]) || is_null($_GET[$param])) {
throw OMB_RemoteServiceException::forRequest(
OAUTH_ENDPOINT_AUTHORIZE,
"Required parameter '$param' not found");
}
}
/* Store given callback for later use. */
if (isset($_GET['oauth_callback']) && $_GET['oauth_callback'] !== '') {
$this->callback = $_GET['oauth_callback'];
if (!OMB_Helper::validateURL($this->callback)) {
throw OMB_RemoteServiceException::forRequest(
OAUTH_ENDPOINT_AUTHORIZE,
'Invalid callback URL specified');
}
}
$this->remote_user = OMB_Profile::fromParameters($_GET, 'omb_listenee');
return $this->remote_user;
}
/**
* Continue the OAuth dance after user authorization
*
* Performs the appropriate actions after user answered the authorization
* request.
*
* @param bool $accepted Whether the user granted authorization
*
* @access public
*
* @return array A two-component array with the values:
* - callback The callback URL or null if none given
* - token The authorized request token or null if not
* authorized.
*/
public function continueUserAuth($accepted)
{
$callback = $this->callback;
if (!$accepted) {
$this->datastore->revoke_token($this->token->key);
$this->token = null;
} else {
$this->datastore->authorize_token($this->token->key);
$this->datastore->saveProfile($this->remote_user);
$this->datastore->saveSubscription($this->user->getIdentifierURI(),
$this->remote_user->getIdentifierURI(),
$this->token);
if (!is_null($this->callback)) {
/* Callback wants to get some informations as well. */
$params = $this->user->asParameters('omb_listener', false);
$params['oauth_token'] = $this->token->key;
$params['omb_version'] = OMB_VERSION;
$callback .= (parse_url($this->callback, PHP_URL_QUERY) ? '&' : '?');
foreach ($params as $k => $v) {
$callback .= OAuthUtil::urlencode_rfc3986($k) . '=' .
OAuthUtil::urlencode_rfc3986($v) . '&';
}
}
}
return array($callback, $this->token);
}
/**
* Echo an access token
*
* Outputs an access token for the query found in $_POST. OMB 0.1 specifies
* that the access token request has to be a POST even if OAuth allows GET
* as well.
*
* @access public
*/
public function writeAccessToken()
{
OMB_Helper::removeMagicQuotesFromRequest();
echo $this->getOAuthServer()->fetch_access_token(
OAuthRequest::from_request('POST')); OAuthRequest::from_request('POST'));
}
/**
* Handle an updateprofile request
*
* Handles an updateprofile request posted to this service. Updates the
* profile through the OMB_Datastore.
*
* @access public
*
* @return OMB_Profile The updated profile
**/
public function handleUpdateProfile() {
list($req, $profile) = $this->handleOMBRequest(OMB_ENDPOINT_UPDATEPROFILE);
$profile->updateFromParameters($req->get_parameters(), 'omb_listenee');
$this->datastore->saveProfile($profile);
$this->finishOMBRequest();
return $profile;
}
/**
* Handle a postnotice request
*
* Handles a postnotice request posted to this service. Saves the notice
* through the OMB_Datastore.
*
* @access public
*
* @return OMB_Notice The received notice
**/
public function handlePostNotice() {
list($req, $profile) = $this->handleOMBRequest(OMB_ENDPOINT_POSTNOTICE);
require_once 'notice.php';
$notice = OMB_Notice::fromParameters($profile, $req->get_parameters());
$this->datastore->saveNotice($notice);
$this->finishOMBRequest();
return $notice;
}
/**
* Handle an OMB request
*
* Performs common OMB request handling.
*
* @param string $uri The URI defining the OMB endpoint being served
*
* @access protected
*
* @return array(OAuthRequest, OMB_Profile)
**/
protected function handleOMBRequest($uri) {
OMB_Helper::removeMagicQuotesFromRequest();
$req = OAuthRequest::from_request('POST');
$listenee = $req->get_parameter('omb_listenee');
try {
list($consumer, $token) = $this->getOAuthServer()->verify_request($req);
} catch (OAuthException $e) {
header('HTTP/1.1 403 Forbidden');
// @debug hack
throw OMB_RemoteServiceException::forRequest($uri,
'Revoked accesstoken for ' . $listenee . ': ' . $e->getMessage());
// @end debug
throw OMB_RemoteServiceException::forRequest($uri,
'Revoked accesstoken for ' . $listenee);
} }
$version = $req->get_parameter('omb_version'); /**
if ($version !== OMB_VERSION) { * Handle an updateprofile request
header('HTTP/1.1 400 Bad Request'); *
throw OMB_RemoteServiceException::forRequest($uri, * Handles an updateprofile request posted to this service. Updates the
'Wrong OMB version ' . $version); * profile through the OMB_Datastore.
*
* @access public
*
* @return OMB_Profile The updated profile
*/
public function handleUpdateProfile()
{
list($req, $profile) = $this->handleOMBRequest(OMB_ENDPOINT_UPDATEPROFILE);
$profile->updateFromParameters($req->get_parameters(), 'omb_listenee');
$this->datastore->saveProfile($profile);
$this->finishOMBRequest();
return $profile;
} }
$profile = $this->datastore->getProfile($listenee); /**
if (is_null($profile)) { * Handle a postnotice request
header('HTTP/1.1 400 Bad Request'); *
throw OMB_RemoteServiceException::forRequest($uri, * Handles a postnotice request posted to this service. Saves the notice
'Unknown remote profile ' . $listenee); * through the OMB_Datastore.
*
* @access public
*
* @return OMB_Notice The received notice
*/
public function handlePostNotice()
{
list($req, $profile) = $this->handleOMBRequest(OMB_ENDPOINT_POSTNOTICE);
$notice = OMB_Notice::fromParameters($profile, $req->get_parameters());
$this->datastore->saveNotice($notice);
$this->finishOMBRequest();
return $notice;
} }
$subscribers = $this->datastore->getSubscriptions($listenee); /**
if (count($subscribers) === 0) { * Handle an OMB request
header('HTTP/1.1 403 Forbidden'); *
throw OMB_RemoteServiceException::forRequest($uri, * Performs common OMB request handling.
'No subscriber for ' . $listenee); *
* @param string $uri The URI defining the OMB endpoint being served
*
* @access protected
*
* @return array(OAuthRequest, OMB_Profile)
*/
protected function handleOMBRequest($uri)
{
OMB_Helper::removeMagicQuotesFromRequest();
$req = OAuthRequest::from_request('POST');
$listenee = $req->get_parameter('omb_listenee');
try {
list($consumer, $token) = $this->getOAuthServer()->verify_request($req);
} catch (OAuthException $e) {
header('HTTP/1.1 403 Forbidden');
throw OMB_RemoteServiceException::forRequest($uri,
'Revoked accesstoken for ' . $listenee);
}
$version = $req->get_parameter('omb_version');
if ($version !== OMB_VERSION) {
header('HTTP/1.1 400 Bad Request');
throw OMB_RemoteServiceException::forRequest($uri,
'Wrong OMB version ' . $version);
}
$profile = $this->datastore->getProfile($listenee);
if (is_null($profile)) {
header('HTTP/1.1 400 Bad Request');
throw OMB_RemoteServiceException::forRequest($uri,
'Unknown remote profile ' . $listenee);
}
$subscribers = $this->datastore->getSubscriptions($listenee);
if (count($subscribers) === 0) {
header('HTTP/1.1 403 Forbidden');
throw OMB_RemoteServiceException::forRequest($uri,
'No subscriber for ' . $listenee);
}
return array($req, $profile);
} }
return array($req, $profile); /**
} * Finishes an OMB request handling
*
* Performs common OMB request handling finishing.
*
* @access protected
*/
protected function finishOMBRequest()
{
header('HTTP/1.1 200 OK');
header('Content-type: text/plain');
/* There should be no clutter but the version. */
echo "omb_version=" . OMB_VERSION;
}
/** /**
* Finishes an OMB request handling * Return an OAuthServer
* *
* Performs common OMB request handling finishing. * Checks whether the OAuthServer is null. If so, initializes it with a
* * default value. Returns the OAuth server.
* @access protected *
**/ * @access protected
protected function finishOMBRequest() { */
header('HTTP/1.1 200 OK'); protected function getOAuthServer()
header('Content-type: text/plain'); {
/* There should be no clutter but the version. */ if (is_null($this->oauth_server)) {
echo "omb_version=" . OMB_VERSION; $this->oauth_server = new OAuthServer($this->datastore);
} $this->oauth_server->add_signature_method(
/**
* Return an OAuthServer
*
* Checks whether the OAuthServer is null. If so, initializes it with a
* default value. Returns the OAuth server.
*
* @access protected
**/
protected function getOAuthServer() {
if (is_null($this->oauth_server)) {
$this->oauth_server = new OAuthServer($this->datastore);
$this->oauth_server->add_signature_method(
new OAuthSignatureMethod_HMAC_SHA1()); new OAuthSignatureMethod_HMAC_SHA1());
} }
return $this->oauth_server; return $this->oauth_server;
}
/**
* Publish a notice
*
* Posts an OMB notice. This includes storing the notice and posting it to
* subscribed users.
*
* @param OMB_Notice $notice The new notice
*
* @access public
*
* @return array An array mapping subscriber URIs to the exception posting to
* them has raised; Empty array if no exception occured
**/
public function postNotice($notice) {
$uri = $this->user->getIdentifierURI();
/* $notice is passed by reference and may change. */
$this->datastore->saveNotice($notice);
$subscribers = $this->datastore->getSubscriptions($uri);
/* No one to post to. */
if (is_null($subscribers)) {
return array();
} }
require_once 'service_consumer.php'; /**
* Publish a notice
*
* Posts an OMB notice. This includes storing the notice and posting it to
* subscribed users.
*
* @param OMB_Notice $notice The new notice
*
* @access public
*
* @return array An array mapping subscriber URIs to the exception posting
* to them has raised; Empty array if no exception occured
*/
public function postNotice($notice)
{
$uri = $this->user->getIdentifierURI();
$err = array(); /* $notice is passed by reference and may change. */
foreach($subscribers as $subscriber) { $this->datastore->saveNotice($notice);
try { $subscribers = $this->datastore->getSubscriptions($uri);
$service = new OMB_Service_Consumer($subscriber['uri'], $uri, $this->datastore);
$service->setToken($subscriber['token'], $subscriber['secret']);
$service->postNotice($notice);
} catch (Exception $e) {
$err[$subscriber['uri']] = $e;
continue;
}
}
return $err;
}
/** /* No one to post to. */
* Publish a profile update if (is_null($subscribers)) {
* return array();
* Posts the current profile as an OMB profile update. This includes updating }
* the stored profile and posting it to subscribed users.
*
* @access public
*
* @return array An array mapping subscriber URIs to the exception posting to
* them has raised; Empty array if no exception occured
**/
public function updateProfile() {
$uri = $this->user->getIdentifierURI();
$this->datastore->saveProfile($this->user); require_once 'service_consumer.php';
$subscribers = $this->datastore->getSubscriptions($uri);
/* No one to post to. */ $err = array();
if (is_null($subscribers)) { foreach ($subscribers as $subscriber) {
return array(); try {
$service = new OMB_Service_Consumer($subscriber['uri'], $uri,
$this->datastore);
$service->setToken($subscriber['token'], $subscriber['secret']);
$service->postNotice($notice);
} catch (Exception $e) {
$err[$subscriber['uri']] = $e;
continue;
}
}
return $err;
} }
require_once 'service_consumer.php'; /**
* Publish a profile update
*
* Posts the current profile as an OMB profile update. This includes
* updating the stored profile and posting it to subscribed users.
*
* @access public
*
* @return array An array mapping subscriber URIs to the exception posting
* to them has raised; Empty array if no exception occured
*/
public function updateProfile()
{
$uri = $this->user->getIdentifierURI();
$err = array(); $this->datastore->saveProfile($this->user);
foreach($subscribers as $subscriber) { $subscribers = $this->datastore->getSubscriptions($uri);
try {
$service = new OMB_Service_Consumer($subscriber['uri'], $uri, $this->datastore); /* No one to post to. */
$service->setToken($subscriber['token'], $subscriber['secret']); if (is_null($subscribers)) {
$service->updateProfile($this->user); return array();
} catch (Exception $e) { }
$err[$subscriber['uri']] = $e;
continue; require_once 'service_consumer.php';
}
$err = array();
foreach ($subscribers as $subscriber) {
try {
$service = new OMB_Service_Consumer($subscriber['uri'], $uri,
$this->datastore);
$service->setToken($subscriber['token'], $subscriber['secret']);
$service->updateProfile($this->user);
} catch (Exception $e) {
$err[$subscriber['uri']] = $e;
continue;
}
}
return $err;
} }
return $err;
}
} }

View File

@ -1,9 +1,6 @@
<?php <?php
/** /**
* Exception stating that a requested service is not available * This file is part of libomb
*
* This exception is raised when OMB_Service is asked to call a service the remote
* server does not provide.
* *
* PHP version 5 * PHP version 5
* *
@ -20,12 +17,20 @@
* You should have received a copy of the GNU Affero General Public License * 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/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
* @package OMB * @package OMB
* @author Adrian Lang <mail@adrianlang.de> * @author Adrian Lang <mail@adrianlang.de>
* @copyright 2009 Adrian Lang * @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
* @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0 * @version 0.1a-20090828
**/ * @link http://adrianlang.de/libomb
class OMB_UnsupportedServiceException extends Exception { */
/**
* Exception stating that a requested service is not available
*
* This exception is raised when OMB_Service is asked to call a service the
* remote server does not provide.
*/
class OMB_UnsupportedServiceException extends Exception
{
} }
?> ?>

View File

@ -1,10 +1,6 @@
<?php <?php
/** /**
* Map XRDS actions to URLs * This file is part of libomb
*
* This interface specifies classes which write the XRDS file announcing
* the OMB server. An instance of an implementing class should be passed to
* OMB_Service_Provider->writeXRDS.
* *
* PHP version 5 * PHP version 5
* *
@ -21,13 +17,31 @@
* You should have received a copy of the GNU Affero General Public License * 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/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
* @package OMB * @package OMB
* @author Adrian Lang <mail@adrianlang.de> * @author Adrian Lang <mail@adrianlang.de>
* @copyright 2009 Adrian Lang * @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
* @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0 * @version 0.1a-20090828
**/ * @link http://adrianlang.de/libomb
*/
interface OMB_XRDS_Mapper { /**
public function getURL($action); * Map XRDS actions to URLs
*
* This interface specifies classes which write the XRDS file announcing
* the OMB server. An instance of an implementing class should be passed to
* OMB_Service_Provider->writeXRDS.
*/
interface OMB_XRDS_Mapper
{
/**
* Fetch an URL for a specified action
*
* Returns the action URL for an action specified by the endpoint URI.
*
* @param string $action The endpoint URI
*
* @return string The action URL
*/
public function getURL($action);
} }
?> ?>

View File

@ -1,10 +1,6 @@
<?php <?php
/** /**
* Write OMB-specific XRDS * This file is part of libomb
*
* This interface specifies classes which write the XRDS file announcing
* the OMB server. An instance of an implementing class should be passed to
* OMB_Service_Provider->writeXRDS.
* *
* PHP version 5 * PHP version 5
* *
@ -21,13 +17,30 @@
* You should have received a copy of the GNU Affero General Public License * 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/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
* @package OMB * @package OMB
* @author Adrian Lang <mail@adrianlang.de> * @author Adrian Lang <mail@adrianlang.de>
* @copyright 2009 Adrian Lang * @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
* @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0 * @version 0.1a-20090828
**/ * @link http://adrianlang.de/libomb
*/
interface OMB_XRDS_Writer { /**
public function writeXRDS($user, $mapper); * Write OMB-specific XRDS
*
* This interface specifies classes which write the XRDS file announcing
* the OMB server. An instance of an implementing class should be passed to
* OMB_Service_Provider->writeXRDS.
*/
interface OMB_XRDS_Writer
{
/**
* Write XRDS
*
* Outputs a XRDS document specifying an OMB service.
*
* @param OMB_profile $user The target user for the OMB service
* @param OMB_XRDS_Mapper $mapper An OMB_XRDS_Mapper providing endpoint URLs
*/
public function writeXRDS($user, $mapper);
} }
?> ?>

View File

@ -258,9 +258,10 @@ var SN = { // StatusNet
form.append('<p class="form_response success">'+result+'</p>'); form.append('<p class="form_response success">'+result+'</p>');
} }
else { else {
// New notice post was successful. If on our timeline, show it!
var notice = document._importNode($('li', data)[0], true);
var notices = $('#notices_primary .notices'); var notices = $('#notices_primary .notices');
if (notices.length > 0) { if (notices.length > 0 && SN.U.belongsOnTimeline(notice)) {
var notice = document._importNode($('li', data)[0], true);
if ($('#'+notice.id).length === 0) { if ($('#'+notice.id).length === 0) {
var notice_irt_value = $('#'+SN.C.S.NoticeInReplyTo).val(); var notice_irt_value = $('#'+SN.C.S.NoticeInReplyTo).val();
var notice_irt = '#notices_primary #notice-'+notice_irt_value; var notice_irt = '#notices_primary #notice-'+notice_irt_value;
@ -281,6 +282,8 @@ var SN = { // StatusNet
} }
} }
else { else {
// Not on a timeline that this belongs on?
// Just show a success message.
result = document._importNode($('title', data)[0], true); result = document._importNode($('title', data)[0], true);
result_title = result.textContent || result.innerHTML; result_title = result.textContent || result.innerHTML;
form.append('<p class="form_response success">'+result_title+'</p>'); form.append('<p class="form_response success">'+result_title+'</p>');
@ -707,6 +710,38 @@ var SN = { // StatusNet
Delete: function() { Delete: function() {
$.cookie(SN.C.S.StatusNetInstance, null); $.cookie(SN.C.S.StatusNetInstance, null);
} }
},
/**
* Check if the current page is a timeline where the current user's
* posts should be displayed immediately on success.
*
* @fixme this should be done in a saner way, with machine-readable
* info about what page we're looking at.
*/
belongsOnTimeline: function(notice) {
var action = $("body").attr('id');
if (action == 'public') {
return true;
}
var profileLink = $('#nav_profile a').attr('href');
if (profileLink) {
var authorUrl = $(notice).find('.entry-title .author a.url').attr('href');
if (authorUrl == profileLink) {
if (action == 'all' || action == 'showstream') {
// Posts always show on your own friends and profile streams.
return true;
}
}
}
// @fixme tag, group, reply timelines should be feasible as well.
// Mismatch between id-based and name-based user/group links currently complicates
// the lookup, since all our inline mentions contain the absolute links but the
// UI links currently on the page use malleable names.
return false;
} }
}, },

View File

@ -51,6 +51,7 @@ class ActivityContext
const POINT = 'point'; const POINT = 'point';
const ATTENTION = 'ostatus:attention'; const ATTENTION = 'ostatus:attention';
const MENTIONED = 'mentioned';
const CONVERSATION = 'ostatus:conversation'; const CONVERSATION = 'ostatus:conversation';
function __construct($element) function __construct($element)
@ -76,8 +77,12 @@ class ActivityContext
$linkRel = $link->getAttribute(ActivityUtils::REL); $linkRel = $link->getAttribute(ActivityUtils::REL);
// XXX: Deprecate this in favour of "mentioned" from Salmon spec
// http://salmon-protocol.googlecode.com/svn/trunk/draft-panzer-salmon-00.html#SALR
if ($linkRel == self::ATTENTION) { if ($linkRel == self::ATTENTION) {
$this->attention[] = $link->getAttribute(self::HREF); $this->attention[] = $link->getAttribute(self::HREF);
} elseif ($linkRel == self::MENTIONED) {
$this->attention[] = $link->getAttribute(self::HREF);
} }
} }
} }

View File

@ -257,6 +257,12 @@ class ActivityUtils
*/ */
static function validateUri($uri) static function validateUri($uri)
{ {
// Check mailto: URIs first
if (preg_match('/^mailto:(.*)$/', $uri, $match)) {
return Validate::email($match[1], common_config('email', 'check_domain'));
}
if (Validate::uri($uri)) { if (Validate::uri($uri)) {
return true; return true;
} }

View File

@ -27,7 +27,7 @@
* @author Jeffery To <jeffery.to@gmail.com> * @author Jeffery To <jeffery.to@gmail.com>
* @author Toby Inkster <mail@tobyinkster.co.uk> * @author Toby Inkster <mail@tobyinkster.co.uk>
* @author Zach Copley <zach@status.net> * @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc. * @copyright 2009-2010 StatusNet, Inc.
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
@ -128,6 +128,7 @@ class ApiAction extends Action
var $max_id = null; var $max_id = null;
var $since_id = null; var $since_id = null;
var $source = null; var $source = null;
var $callback = null;
var $access = self::READ_ONLY; // read (default) or read-write var $access = self::READ_ONLY; // read (default) or read-write
@ -147,6 +148,7 @@ class ApiAction extends Action
parent::prepare($args); parent::prepare($args);
$this->format = $this->arg('format'); $this->format = $this->arg('format');
$this->callback = $this->arg('callback');
$this->page = (int)$this->arg('page', 1); $this->page = (int)$this->arg('page', 1);
$this->count = (int)$this->arg('count', 20); $this->count = (int)$this->arg('count', 20);
$this->max_id = (int)$this->arg('max_id', 0); $this->max_id = (int)$this->arg('max_id', 0);
@ -463,6 +465,7 @@ class ApiAction extends Action
function twitterRssEntryArray($notice) function twitterRssEntryArray($notice)
{ {
$profile = $notice->getProfile(); $profile = $notice->getProfile();
$entry = array(); $entry = array();
// We trim() to avoid extraneous whitespace in the output // We trim() to avoid extraneous whitespace in the output
@ -735,14 +738,16 @@ class ApiAction extends Action
'xmlns:statusnet' => 'http://status.net/schema/api/1/')); 'xmlns:statusnet' => 'http://status.net/schema/api/1/'));
if (is_array($notice)) { if (is_array($notice)) {
foreach ($notice as $n) { $notice = new ArrayWrapper($notice);
$twitter_status = $this->twitterStatusArray($n); }
$this->showTwitterXmlStatus($twitter_status);
} while ($notice->fetch()) {
} else { try {
while ($notice->fetch()) {
$twitter_status = $this->twitterStatusArray($notice); $twitter_status = $this->twitterStatusArray($notice);
$this->showTwitterXmlStatus($twitter_status); $this->showTwitterXmlStatus($twitter_status);
} catch (Exception $e) {
common_log(LOG_ERR, $e->getMessage());
continue;
} }
} }
@ -790,14 +795,16 @@ class ApiAction extends Action
$this->element('ttl', null, '40'); $this->element('ttl', null, '40');
if (is_array($notice)) { if (is_array($notice)) {
foreach ($notice as $n) { $notice = new ArrayWrapper($notice);
$entry = $this->twitterRssEntryArray($n); }
$this->showTwitterRssItem($entry);
} while ($notice->fetch()) {
} else { try {
while ($notice->fetch()) {
$entry = $this->twitterRssEntryArray($notice); $entry = $this->twitterRssEntryArray($notice);
$this->showTwitterRssItem($entry); $this->showTwitterRssItem($entry);
} catch (Exception $e) {
common_log(LOG_ERR, $e->getMessage());
// continue on exceptions
} }
} }
@ -833,12 +840,15 @@ class ApiAction extends Action
$this->element('subtitle', null, $subtitle); $this->element('subtitle', null, $subtitle);
if (is_array($notice)) { if (is_array($notice)) {
foreach ($notice as $n) { $notice = new ArrayWrapper($notice);
$this->raw($n->asAtomEntry()); }
}
} else { while ($notice->fetch()) {
while ($notice->fetch()) { try {
$this->raw($notice->asAtomEntry()); $this->raw($notice->asAtomEntry());
} catch (Exception $e) {
common_log(LOG_ERR, $e->getMessage());
continue;
} }
} }
@ -1033,14 +1043,16 @@ class ApiAction extends Action
$statuses = array(); $statuses = array();
if (is_array($notice)) { if (is_array($notice)) {
foreach ($notice as $n) { $notice = new ArrayWrapper($notice);
$twitter_status = $this->twitterStatusArray($n); }
array_push($statuses, $twitter_status);
} while ($notice->fetch()) {
} else { try {
while ($notice->fetch()) {
$twitter_status = $this->twitterStatusArray($notice); $twitter_status = $this->twitterStatusArray($notice);
array_push($statuses, $twitter_status); array_push($statuses, $twitter_status);
} catch (Exception $e) {
common_log(LOG_ERR, $e->getMessage());
continue;
} }
} }
@ -1177,9 +1189,8 @@ class ApiAction extends Action
header('Content-Type: application/json; charset=utf-8'); header('Content-Type: application/json; charset=utf-8');
// Check for JSONP callback // Check for JSONP callback
$callback = $this->arg('callback'); if (isset($this->callback)) {
if ($callback) { print $this->callback . '(';
print $callback . '(';
} }
break; break;
case 'rss': case 'rss':
@ -1208,8 +1219,7 @@ class ApiAction extends Action
case 'json': case 'json':
// Check for JSONP callback // Check for JSONP callback
$callback = $this->arg('callback'); if (isset($this->callback)) {
if ($callback) {
print ')'; print ')';
} }
break; break;
@ -1239,7 +1249,10 @@ class ApiAction extends Action
$status_string = ClientErrorAction::$status[$code]; $status_string = ClientErrorAction::$status[$code];
header('HTTP/1.1 '.$code.' '.$status_string); // Do not emit error header for JSONP
if (!isset($this->callback)) {
header('HTTP/1.1 '.$code.' '.$status_string);
}
if ($format == 'xml') { if ($format == 'xml') {
$this->initDocument('xml'); $this->initDocument('xml');
@ -1272,7 +1285,10 @@ class ApiAction extends Action
$status_string = ServerErrorAction::$status[$code]; $status_string = ServerErrorAction::$status[$code];
header('HTTP/1.1 '.$code.' '.$status_string); // Do not emit error header for JSONP
if (!isset($this->callback)) {
header('HTTP/1.1 '.$code.' '.$status_string);
}
if ($content_type == 'xml') { if ($content_type == 'xml') {
$this->initDocument('xml'); $this->initDocument('xml');
@ -1376,6 +1392,34 @@ class ApiAction extends Action
} }
} }
function getTargetProfile($id)
{
if (empty($id)) {
// Twitter supports these other ways of passing the user ID
if (is_numeric($this->arg('id'))) {
return Profile::staticGet($this->arg('id'));
} else if ($this->arg('id')) {
$nickname = common_canonical_nickname($this->arg('id'));
return Profile::staticGet('nickname', $nickname);
} else if ($this->arg('user_id')) {
// This is to ensure that a non-numeric user_id still
// overrides screen_name even if it doesn't get used
if (is_numeric($this->arg('user_id'))) {
return Profile::staticGet('id', $this->arg('user_id'));
}
} else if ($this->arg('screen_name')) {
$nickname = common_canonical_nickname($this->arg('screen_name'));
return Profile::staticGet('nickname', $nickname);
}
} else if (is_numeric($id)) {
return Profile::staticGet($id);
} else {
$nickname = common_canonical_nickname($id);
return Profile::staticGet('nickname', $nickname);
}
}
function getTargetGroup($id) function getTargetGroup($id)
{ {
if (empty($id)) { if (empty($id)) {

View File

@ -227,7 +227,7 @@ class ApiAuthAction extends ApiAction
} catch (OAuthException $e) { } catch (OAuthException $e) {
common_log(LOG_WARNING, 'API OAuthException - ' . $e->getMessage()); common_log(LOG_WARNING, 'API OAuthException - ' . $e->getMessage());
$this->showAuthError(); $this->clientError($e->getMessage(), 401, $this->format);
exit; exit;
} }
} }
@ -265,7 +265,7 @@ class ApiAuthAction extends ApiAction
// show error if the user clicks 'cancel' // show error if the user clicks 'cancel'
$this->showAuthError(); $this->clientError("Could not authenticate you.", 401, $this->format);
exit; exit;
} else { } else {
@ -298,7 +298,7 @@ class ApiAuthAction extends ApiAction
$proxy, $proxy,
$ip); $ip);
common_log(LOG_WARNING, $msg); common_log(LOG_WARNING, $msg);
$this->showAuthError(); $this->clientError("Could not authenticate you.", 401, $this->format);
exit; exit;
} }
} }
@ -345,36 +345,4 @@ class ApiAuthAction extends ApiAction
} }
} }
} }
/**
* Output an authentication error message. Use XML or JSON if one
* of those formats is specified, otherwise output plain text
*
* @return void
*/
function showAuthError()
{
header('HTTP/1.1 401 Unauthorized');
$msg = 'Could not authenticate you.';
if ($this->format == 'xml') {
header('Content-Type: application/xml; charset=utf-8');
$this->startXML();
$this->elementStart('hash');
$this->element('error', null, $msg);
$this->element('request', null, $_SERVER['REQUEST_URI']);
$this->elementEnd('hash');
$this->endXML();
} elseif ($this->format == 'json') {
header('Content-Type: application/json; charset=utf-8');
$error_array = array('error' => $msg,
'request' => $_SERVER['REQUEST_URI']);
print(json_encode($error_array));
} else {
header('Content-type: text/plain');
print "$msg\n";
}
}
} }

Some files were not shown because too many files have changed in this diff Show More