diff --git a/classes/Profile.php b/classes/Profile.php index a45511fe54..1c8dbcc252 100644 --- a/classes/Profile.php +++ b/classes/Profile.php @@ -761,6 +761,17 @@ class Profile extends Managed_DataObject return Subscription::exists($this, $other); } + function readableBy(Profile $other=null) + { + // If it's not a private stream, it's readable by anyone + if (!$this->isPrivateStream()) { + return true; + } + + // If it's a private stream, $other must be a subscriber to $this + return is_null($other) ? false : $other->isSubscribed($this); + } + /** * Check if a pending subscription request is outstanding for this... * diff --git a/lib/noticestreamaction.php b/lib/noticestreamaction.php index bf09b63780..fb592915a7 100644 --- a/lib/noticestreamaction.php +++ b/lib/noticestreamaction.php @@ -13,8 +13,13 @@ abstract class NoticestreamAction extends ProfileAction $this->doStreamPreparation(); // fetch the actual stream stuff - $stream = $this->getStream(); - $this->notice = $stream->getNotices(($this->page-1) * NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1); + try { + $stream = $this->getStream(); + $this->notice = $stream->getNotices(($this->page-1) * NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1); + } catch (PrivateStreamException $e) { + $this->notice = new Notice(); + $this->notice->whereAdd('FALSE'); + } if ($this->page > 1 && $this->notice->N == 0) { // TRANS: Client error when page not found (404). diff --git a/lib/privatestreamexception.php b/lib/privatestreamexception.php new file mode 100644 index 0000000000..ed9f3e0d5a --- /dev/null +++ b/lib/privatestreamexception.php @@ -0,0 +1,31 @@ + + * @copyright 2016 Free Software Foundation, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 + */ + +class PrivateStreamException extends AuthorizationException +{ + var $owner = null; // owner of the private stream + var $reader = null; // reader, may be null if not logged in + + public function __construct(Profile $owner, Profile $reader=null) + { + $this->owner = $owner; + $this->reader = $reader; + + // TRANS: Message when a private stream attemps to be read by unauthorized third party. + $msg = sprintf(_m('This stream is protected and only authorized subscribers may see its contents.')); + + // If $reader is a profile, authentication has been made but still not accepted (403), + // otherwise authentication may give access to this resource (401). + parent::__construct($msg, ($reader instanceof Profile ? 403 : 401)); + } +} diff --git a/lib/profilenoticestream.php b/lib/profilenoticestream.php index 1fa795d320..3c8de05855 100644 --- a/lib/profilenoticestream.php +++ b/lib/profilenoticestream.php @@ -74,7 +74,7 @@ class ProfileNoticeStream extends ScopingNoticeStream function getNotices($offset, $limit, $since_id=null, $max_id=null) { if ($this->impossibleStream()) { - return new ArrayWrapper(array()); + throw new PrivateStreamException($this->streamProfile, $this->userProfile); } else { return parent::getNotices($offset, $limit, $since_id, $max_id); } @@ -82,12 +82,8 @@ class ProfileNoticeStream extends ScopingNoticeStream function impossibleStream() { - $user = User::getKV('id', $this->streamProfile->id); - - // If it's a private stream, and no user or not a subscriber - - if (!empty($user) && $user->private_stream && - (empty($this->userProfile) || !$this->userProfile->isSubscribed($this->streamProfile))) { + if (!$this->streamProfile->readableBy($this->userProfile)) { + // cannot read because it's a private stream and either noone's logged in or they are not subscribers return true; }