From 32145484c28323c95c0f84a274fb13714b738a3d Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Tue, 29 Mar 2011 11:53:26 -0400 Subject: [PATCH] Disallow repeats (retweets) of private notices We disallow repeating a notice (or whatever) if the scope of the notice is too private. So, only notices that are public scope (available to everyone in the world) or site scope (available to everyone on the site) can be repeated. Enforce this rule at a low level in Notice.php, and in the API, commands, and Web UI. Repeat button doesn't appear on tightly-scoped notices in the Web UI. --- actions/apistatusesretweet.php | 20 ++++++++++++++++++++ actions/repeat.php | 15 +++++++++++++++ classes/Notice.php | 14 ++++++++++++++ lib/command.php | 17 ++++++++++++++++- lib/noticelistitem.php | 26 +++++++++++++++----------- 5 files changed, 80 insertions(+), 12 deletions(-) diff --git a/actions/apistatusesretweet.php b/actions/apistatusesretweet.php index ecc4a3f033..2bc9092ba6 100644 --- a/actions/apistatusesretweet.php +++ b/actions/apistatusesretweet.php @@ -85,8 +85,27 @@ class ApiStatusesRetweetAction extends ApiAuthAction return false; } + // Is it OK to repeat that notice (general enough scope)? + + if ($this->original->scope != Notice::SITE_SCOPE && + $this->original->scope != Notice::PUBLIC_SCOPE) { + $this->clientError(_('You may not repeat a private notice.'), + 403, + $this->format); + return false; + } + $profile = $this->user->getProfile(); + // Can the profile actually see that notice? + + if (!$this->original->inScope($profile)) { + $this->clientError(_('No access to that notice.'), + 403, + $this->format); + return false; + } + if ($profile->hasRepeated($id)) { // TRANS: Client error displayed trying to re-repeat a notice through the API. $this->clientError(_('Already repeated that notice.'), @@ -94,6 +113,7 @@ class ApiStatusesRetweetAction extends ApiAuthAction return false; } + return true; } diff --git a/actions/repeat.php b/actions/repeat.php index 869c2ddd4e..4201a4ce95 100644 --- a/actions/repeat.php +++ b/actions/repeat.php @@ -73,6 +73,14 @@ class RepeatAction extends Action return false; } + // Is it OK to repeat that notice (general enough scope)? + + if ($this->notice->scope != Notice::SITE_SCOPE && + $this->notice->scope != Notice::PUBLIC_SCOPE) { + $this->clientError(_('You may not repeat a private notice.'), + 403); + } + if ($this->user->id == $this->notice->profile_id) { // TRANS: Client error displayed when trying to repeat an own notice. $this->clientError(_('You cannot repeat your own notice.')); @@ -88,6 +96,13 @@ class RepeatAction extends Action $profile = $this->user->getProfile(); + // Can the profile actually see that notice? + + if (!$this->notice->inScope($profile)) { + $this->clientError(_('No access to that notice.'), 403); + } + + if ($profile->hasRepeated($id)) { // TRANS: Client error displayed when trying to repeat an already repeated notice. $this->clientError(_('You already repeated that notice.')); diff --git a/classes/Notice.php b/classes/Notice.php index 3780d52d56..a6e4566e4b 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -90,6 +90,7 @@ class Notice extends Memcached_DataObject const LOCAL_NONPUBLIC = -1; const GATEWAY = -2; + const PUBLIC_SCOPE = 0; // Useful fake constant const SITE_SCOPE = 1; const ADDRESSEE_SCOPE = 2; const GROUP_SCOPE = 4; @@ -344,6 +345,19 @@ class Notice extends Memcached_DataObject // Handle repeat case if (isset($repeat_of)) { + + // Check for a private one + + $repeat = Notice::staticGet('id', $repeat_of); + + if (!empty($repeat) && + $repeat->scope != Notice::SITE_SCOPE && + $repeat->scope != Notice::PUBLIC_SCOPE) { + throw new ClientException(_('Cannot repeat a private notice.'), 403); + } + + // XXX: Check for access...? + $notice->repeat_of = $repeat_of; } else { $notice->reply_to = self::getReplyTo($reply_to, $profile_id, $source, $final); diff --git a/lib/command.php b/lib/command.php index 5b9964c5b1..35d0702684 100644 --- a/lib/command.php +++ b/lib/command.php @@ -544,7 +544,22 @@ class RepeatCommand extends Command return; } - if ($this->user->getProfile()->hasRepeated($notice->id)) { + // Is it OK to repeat that notice (general enough scope)? + + if ($notice->scope != Notice::SITE_SCOPE && + $notice->scope != Notice::PUBLIC_SCOPE) { + $channel->error($this->user, _('You may not repeat a private notice.')); + } + + $profile = $this->user->getProfile(); + + // Can the profile actually see that notice? + + if (!$notice->inScope($profile)) { + $channel->error($this->user, _('You have no access to that notice.')); + } + + if ($profile->hasRepeated($notice->id)) { // TRANS: Error text shown when trying to repeat an notice that was already repeated by the user. $channel->error($this->user, _('Already repeated that notice.')); return; diff --git a/lib/noticelistitem.php b/lib/noticelistitem.php index 46f15f551d..097a5d06c4 100644 --- a/lib/noticelistitem.php +++ b/lib/noticelistitem.php @@ -596,17 +596,21 @@ class NoticeListItem extends Widget function showRepeatForm() { - $user = common_current_user(); - if ($user && $user->id != $this->notice->profile_id) { - $this->out->text(' '); - $profile = $user->getProfile(); - if ($profile->hasRepeated($this->notice->id)) { - $this->out->element('span', array('class' => 'repeated', - 'title' => _('Notice repeated')), - _('Repeated')); - } else { - $rf = new RepeatForm($this->out, $this->notice); - $rf->show(); + if ($this->notice->scope == Notice::PUBLIC_SCOPE || + $this->notice->scope == Notice::SITE_SCOPE) { + $user = common_current_user(); + if (!empty($user) && + $user->id != $this->notice->profile_id) { + $this->out->text(' '); + $profile = $user->getProfile(); + if ($profile->hasRepeated($this->notice->id)) { + $this->out->element('span', array('class' => 'repeated', + 'title' => _('Notice repeated')), + _('Repeated')); + } else { + $rf = new RepeatForm($this->out, $this->notice); + $rf->show(); + } } } }