Commit 073e3a15 authored by Zach Copley's avatar Zach Copley

Merge branch 'testing' of gitorious.org:statusnet/mainline into testing

* 'testing' of gitorious.org:statusnet/mainline:
  OStatus remote sending test cases. Doesn't actually run within PHPUnit right now, must be run from command line -- specify base URLs to two StatusNet sites that will be able to communicate with each other.
  Math_BigInteger doesn't correctly handle serialization/deserialization for a value of 0, which can end up spewing notices to output and otherwise intefering with Salmon signature setup and verification when using memcached.
  Log backtraces for non-ClientException exceptions caught at the top-level handler.
  Confirm there's actually user and domain portions of acct string before assigning things from output of explode(); avoids notice message when invalid input passed to main/xrd
  Fixing HTTP Header LRDD parsing (sites in subdirectories need this)
  Replace the "give up and dump object" attachment view fallback with a client-side redirect to the target URL, which will at least be useful.
  ignore unrecognized object types
  Pull <atom:author> info as well as <activity:actor> when we have an old-style ActivityStreams feed. This fixes subscription setup for Cliqset feeds, which currently have a bogus activity:actor/atom:id but a good atom:author/atom:uri
  Accept 'tag' and other non-http id URIs in Ostatus_profile::getActivityObjectProfileURI().
parents a0a9acb9 3678e7b8
......@@ -324,10 +324,10 @@ function main()
$cac = new ClientErrorAction($cex->getMessage(), $cex->getCode());
$cac->showPage();
} catch (ServerException $sex) { // snort snort guffaw
$sac = new ServerErrorAction($sex->getMessage(), $sex->getCode());
$sac = new ServerErrorAction($sex->getMessage(), $sex->getCode(), $sex);
$sac->showPage();
} catch (Exception $ex) {
$sac = new ServerErrorAction($ex->getMessage());
$sac = new ServerErrorAction($ex->getMessage(), 500, $ex);
$sac->showPage();
}
}
......
......@@ -156,7 +156,11 @@ class ActivityObject
{
$this->type = self::PERSON; // XXX: is this fair?
$this->title = $this->_childContent($element, self::NAME);
$this->id = $this->_childContent($element, self::URI);
$id = $this->_childContent($element, self::URI);
if (ActivityUtils::validateUri($id)) {
$this->id = $id;
}
if (empty($this->id)) {
$email = $this->_childContent($element, self::EMAIL);
......@@ -169,6 +173,15 @@ class ActivityObject
private function _fromAtomEntry($element)
{
if ($element->localName == 'actor') {
// Old-fashioned <activity:actor>...
// First pull anything from <author>, then we'll add on top.
$author = ActivityUtils::child($element->parentNode, 'author');
if ($author) {
$this->_fromAuthor($author);
}
}
$this->type = $this->_childContent($element, Activity::OBJECTTYPE,
Activity::SPEC);
......@@ -176,7 +189,11 @@ class ActivityObject
$this->type = ActivityObject::NOTE;
}
$this->id = $this->_childContent($element, self::ID);
$id = $this->_childContent($element, self::ID);
if (ActivityUtils::validateUri($id)) {
$this->id = $id;
}
$this->summary = ActivityUtils::childHtmlContent($element, self::SUMMARY);
$this->content = ActivityUtils::getContent($element);
......
......@@ -240,4 +240,26 @@ class ActivityUtils
throw new ClientException(_("Can't handle embedded Base64 content yet."));
}
}
/**
* Is this a valid URI for remote profile/notice identification?
* Does not have to be a resolvable URL.
* @param string $uri
* @return boolean
*/
static function validateUri($uri)
{
if (Validate::uri($uri)) {
return true;
}
// Possibly an upstream bug; tag: URIs aren't validated properly
// unless you explicitly ask for them. All other schemes are accepted
// for basic URI validation without asking.
if (Validate::uri($uri, array('allowed_scheme' => array('tag')))) {
return true;
}
return false;
}
}
......@@ -306,7 +306,7 @@ class Attachment extends AttachmentListItem
function showRepresentation() {
if (empty($this->oembed->type)) {
if (empty($this->attachment->mimetype)) {
$this->out->element('pre', null, 'oh well... not sure how to handle the following: ' . print_r($this->attachment, true));
$this->showFallback();
} else {
switch ($this->attachment->mimetype) {
case 'image/gif':
......@@ -332,6 +332,8 @@ class Attachment extends AttachmentListItem
$this->out->element('param', array('name' => 'autoStart', 'value' => 1));
$this->out->elementEnd('object');
break;
default:
$this->showFallback();
}
}
} else {
......@@ -354,9 +356,23 @@ class Attachment extends AttachmentListItem
break;
default:
$this->out->element('pre', null, 'oh well... not sure how to handle the following oembed: ' . print_r($this->oembed, true));
$this->showFallback();
}
}
}
function showFallback()
{
// If we don't know how to display an attachment inline, we probably
// shouldn't have gotten to this point.
//
// But, here we are... displaying details on a file or remote URL
// either on the main view or in an ajax-loaded lightbox. As a lesser
// of several evils, we'll try redirecting to the actual target via
// client-side JS.
common_log(LOG_ERR, "Empty or unknown type for file id {$this->attachment->id}; falling back to client-side redirect.");
$this->out->raw('<script>window.location = ' . json_encode($this->attachment->url) . ';</script>');
}
}
......@@ -62,15 +62,18 @@ class ServerErrorAction extends ErrorAction
504 => 'Gateway Timeout',
505 => 'HTTP Version Not Supported');
function __construct($message='Error', $code=500)
function __construct($message='Error', $code=500, $ex=null)
{
parent::__construct($message, $code);
$this->default = 500;
// Server errors must be logged.
common_log(LOG_ERR, "ServerErrorAction: $code $message");
$log = "ServerErrorAction: $code $message";
if ($ex) {
$log .= "\n" . $ex->getTraceAsString();
}
common_log(LOG_ERR, $log);
}
// XXX: Should these error actions even be invokable via URI?
......
......@@ -35,9 +35,13 @@ class UserxrdAction extends XrdAction
$this->uri = Discovery::normalize($this->uri);
if (Discovery::isWebfinger($this->uri)) {
list($nick, $domain) = explode('@', substr(urldecode($this->uri), 5));
$nick = common_canonical_nickname($nick);
$this->user = User::staticGet('nickname', $nick);
$parts = explode('@', substr(urldecode($this->uri), 5));
if (count($parts) == 2) {
list($nick, $domain) = $parts;
// @fixme confirm the domain too
$nick = common_canonical_nickname($nick);
$this->user = User::staticGet('nickname', $nick);
}
} else {
$this->user = User::staticGet('uri', $this->uri);
}
......
......@@ -27,8 +27,6 @@
* @link http://status.net/
*/
require_once 'Crypt/RSA.php';
class Magicsig extends Memcached_DataObject
{
......@@ -102,16 +100,16 @@ class Magicsig extends Memcached_DataObject
public function generate($user_id)
{
$rsa = new Crypt_RSA();
$rsa = new SafeCrypt_RSA();
$keypair = $rsa->createKey();
$rsa->loadKey($keypair['privatekey']);
$this->privateKey = new Crypt_RSA();
$this->privateKey = new SafeCrypt_RSA();
$this->privateKey->loadKey($keypair['privatekey']);
$this->publicKey = new Crypt_RSA();
$this->publicKey = new SafeCrypt_RSA();
$this->publicKey->loadKey($keypair['publickey']);
$this->user_id = $user_id;
......@@ -163,7 +161,7 @@ class Magicsig extends Memcached_DataObject
{
common_log(LOG_DEBUG, "Adding ".$type." key: (".$mod .', '. $exp .")");
$rsa = new Crypt_RSA();
$rsa = new SafeCrypt_RSA();
$rsa->signatureMode = CRYPT_RSA_SIGNATURE_PKCS1;
$rsa->setHash('sha256');
$rsa->modulus = new Math_BigInteger(base64_url_decode($mod), 256);
......
......@@ -442,6 +442,17 @@ class Ostatus_profile extends Memcached_DataObject
{
$activity = new Activity($entry, $feed);
switch ($activity->object->type) {
case ActivityObject::ARTICLE:
case ActivityObject::BLOGENTRY:
case ActivityObject::NOTE:
case ActivityObject::STATUS:
case ActivityObject::COMMENT:
break;
default:
throw new ClientException("Can't handle that kind of post.");
}
if ($activity->verb == ActivityVerb::POST) {
$this->processPost($activity, $source);
} else {
......@@ -1140,35 +1151,45 @@ class Ostatus_profile extends Memcached_DataObject
/**
* @param Activity $activity
* @return mixed matching Ostatus_profile or false if none known
* @throws ServerException if feed info invalid
*/
public static function getActorProfile($activity)
{
return self::getActivityObjectProfile($activity->actor);
}
/**
* @param ActivityObject $activity
* @return mixed matching Ostatus_profile or false if none known
* @throws ServerException if feed info invalid
*/
protected static function getActivityObjectProfile($object)
{
$uri = self::getActivityObjectProfileURI($object);
return Ostatus_profile::staticGet('uri', $uri);
}
protected static function getActorProfileURI($activity)
{
return self::getActivityObjectProfileURI($activity->actor);
}
/**
* @param Activity $activity
* Get the identifier URI for the remote entity described
* by this ActivityObject. This URI is *not* guaranteed to be
* a resolvable HTTP/HTTPS URL.
*
* @param ActivityObject $object
* @return string
* @throws ServerException
* @throws ServerException if feed info invalid
*/
protected static function getActivityObjectProfileURI($object)
{
$opts = array('allowed_schemes' => array('http', 'https'));
if ($object->id && Validate::uri($object->id, $opts)) {
return $object->id;
if ($object->id) {
if (ActivityUtils::validateUri($object->id)) {
return $object->id;
}
}
if ($object->link && Validate::uri($object->link, $opts)) {
// If the id is missing or invalid (we've seen feeds mistakenly listing
// things like local usernames in that field) then we'll use the profile
// page link, if valid.
if ($object->link && common_valid_http_url($object->link)) {
return $object->link;
}
throw new ServerException("No author ID URI found");
......
......@@ -195,7 +195,7 @@ class Discovery_LRDD_Link_Header implements Discovery_LRDD
// return false;
}
return Discovery_LRDD_Link_Header::parseHeader($link_header);
return array(Discovery_LRDD_Link_Header::parseHeader($link_header));
}
protected static function parseHeader($header)
......
......@@ -11,7 +11,7 @@ class LinkHeader
preg_match('/^<[^>]+>/', $str, $uri_reference);
//if (empty($uri_reference)) return;
$this->uri = trim($uri_reference[0], '<>');
$this->href = trim($uri_reference[0], '<>');
$this->rel = array();
$this->type = null;
......
<?php
require_once 'Crypt/RSA.php';
/**
* Crypt_RSA stores a Math_BigInteger with value 0, which triggers a bug
* in Math_BigInteger's wakeup function which spews notices to log or output.
* This wrapper replaces it with a version that survives serialization.
*/
class SafeCrypt_RSA extends Crypt_RSA
{
function __construct()
{
parent::__construct();
$this->zero = new SafeMath_BigInteger();
}
}
<?php
require_once 'Math/BigInteger.php';
/**
* Crypt_RSA stores a Math_BigInteger with value 0, which triggers a bug
* in Math_BigInteger's wakeup function which spews notices to log or output.
* This wrapper replaces it with a version that survives serialization.
*/
class SafeMath_BigInteger extends Math_BigInteger
{
function __wakeup()
{
if ($this->hex == '') {
$this->hex = '0';
}
parent::__wakeup();
}
}
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment