diff --git a/plugins/Repeat/Controller/Repeat.php b/plugins/Repeat/Controller/Repeat.php index 3f453095f5..84a5049201 100644 --- a/plugins/Repeat/Controller/Repeat.php +++ b/plugins/Repeat/Controller/Repeat.php @@ -1,6 +1,6 @@ $user->getId(), 'repeat_of' => $id]; + $user = Common::ensureLoggedIn(); + $opts = ['actor_id' => $user->getId(), 'repeat_of' => $id]; $note_already_repeated = DB::count('note_repeat', $opts) >= 1; - if (is_null($note_already_repeated)) { - throw new NoSuchNoteException(); + + // Before the form is rendered for the first time + if (\is_null($note_already_repeated)) { + throw new ClientException(_m('Note already repeated!')); } - $note = Note::getWithPK(['id' => $id]); + $note = Note::getWithPK(['id' => $id]); $form_add_to_repeat = Form::create([ ['add_repeat', SubmitType::class, [ 'label' => _m('Repeat note!'), 'attr' => [ - 'title' => _m('Repeat this note!') + 'title' => _m('Repeat this note!'), ], ], ], @@ -72,34 +75,38 @@ class Repeat extends Controller $form_add_to_repeat->handleRequest($request); if ($form_add_to_repeat->isSubmitted()) { + // If the user goes back to the form, again + if (DB::count('note_repeat', ['actor_id' => $user->getId(), 'repeat_of' => $id]) >= 1) { + throw new ClientException(_m('Note already repeated!')); + } - if (!is_null($note)) { + if (!\is_null($note)) { $actor_id = $user->getId(); - $content = $note->getContent(); + $content = $note->getContent(); // Create a new note with the same content as the original $repeat = Note::create([ - 'actor_id' => $actor_id, - 'content' => $content, + 'actor_id' => $actor_id, + 'content' => $content, 'content_type' => $note->getContentType(), - 'rendered' => $note->getRendered(), - 'is_local' => true, + 'rendered' => $note->getRendered(), + 'is_local' => true, ]); - DB::persist($repeat); // Update DB + DB::persist($repeat); DB::flush(); // Find the id of the note we just created $repeat_id = $repeat->getId(); - $og_id = $note->getId(); + $og_id = $note->getId(); // Add it to note_repeat table - if (!is_null($repeat_id)) { + if (!\is_null($repeat_id)) { DB::persist(NoteRepeat::create([ - 'note_id' => $repeat_id, - 'actor_id' => $actor_id, - 'repeat_of' => $og_id + 'note_id' => $repeat_id, + 'actor_id' => $actor_id, + 'repeat_of' => $og_id, ])); } @@ -107,32 +114,42 @@ class Repeat extends Controller DB::flush(); } - if (array_key_exists('from', $get_params = $this->params())) { - # TODO anchor on element id - throw new RedirectException($get_params['from']); + // Redirect user to where they came from + // Prevent open redirect + if (\array_key_exists('from', (array) $get_params = $this->params())) { + if (Router::isAbsolute($get_params['from'])) { + Log::warning("Actor {$actor_id} attempted to reply to a note and then get redirected to another host, or the URL was invalid ({$get_params['from']})"); + throw new ClientException(_m('Can not redirect to outside the website from here'), 400); // 400 Bad request (deceptive) + } else { + // TODO anchor on element id + throw new RedirectException($get_params['from']); + } + } else { + // If we don't have a URL to return to, go to the instance root + throw new RedirectException('root'); } } return [ - '_template' => 'repeat/add_to_repeats.html.twig', - 'note' => $note, + '_template' => 'repeat/add_to_repeats.html.twig', + 'note' => $note, 'add_repeat' => $form_add_to_repeat->createView(), ]; } /** - * @throws RedirectException - * @throws NoSuchNoteException - * @throws InvalidFormException * @throws \App\Util\Exception\ServerException + * @throws ClientException * @throws NoLoggedInUser + * @throws NoSuchNoteException + * @throws RedirectException */ public function repeatRemoveNote(Request $request, int $id): array { - $user = Common::ensureLoggedIn(); - $opts = ['id' => $id]; + $user = Common::ensureLoggedIn(); + $opts = ['id' => $id]; $remove_repeat_note = DB::find('note', $opts); - if (is_null($remove_repeat_note)) { + if (\is_null($remove_repeat_note)) { throw new NoSuchNoteException(); } @@ -141,7 +158,7 @@ class Repeat extends Controller [ 'label' => _m('Remove repeat'), 'attr' => [ - 'title' => _m('Remove note from repeats.') + 'title' => _m('Remove note from repeats.'), ], ], ], @@ -155,22 +172,31 @@ class Repeat extends Controller DB::flush(); // Remove from the note_repeat table - $opts = ['note_id' => $id]; + $opts = ['note_id' => $id]; $remove_note_repeat = DB::find('note_repeat', $opts); DB::remove($remove_note_repeat); DB::flush(); } - if (array_key_exists('from', $get_params = $this->params())) { - # TODO anchor on element id - throw new RedirectException($get_params['from']); + // Redirect user to where they came from + // Prevent open redirect + if (\array_key_exists('from', (array) $get_params = $this->params())) { + if (Router::isAbsolute($get_params['from'])) { + Log::warning("Actor {$actor_id} attempted to reply to a note and then get redirected to another host, or the URL was invalid ({$get_params['from']})"); + throw new ClientException(_m('Can not redirect to outside the website from here'), 400); // 400 Bad request (deceptive) + } else { + // TODO anchor on element id + throw new RedirectException($get_params['from']); + } + } else { + throw new RedirectException('root'); // If we don't have a URL to return to, go to the instance root } } return [ - '_template' => 'repeat/remove_from_repeats.html.twig', - 'note' => $remove_repeat_note, - 'remove_repeat' => $form_remove_repeat->createView(), + '_template' => 'repeat/remove_from_repeats.html.twig', + 'note' => $remove_repeat_note, + 'remove_repeat' => $form_remove_repeat->createView(), ]; } } diff --git a/plugins/Repeat/Repeat.php b/plugins/Repeat/Repeat.php index 880a53393e..a517ea8f54 100644 --- a/plugins/Repeat/Repeat.php +++ b/plugins/Repeat/Repeat.php @@ -23,18 +23,20 @@ namespace Plugin\Repeat; use App\Core\DB\DB; use App\Core\Event; +use function App\Core\I18n\_m; use App\Core\Modules\NoteHandlerPlugin; use App\Core\Router\RouteLoader; use App\Core\Router\Router; use App\Entity\Actor; use App\Entity\Note; use App\Util\Common; +use App\Util\Exception\ClientException; use App\Util\Exception\DuplicateFoundException; use App\Util\Exception\InvalidFormException; -use App\Util\Exception\NoLoggedInUser; use App\Util\Exception\NoSuchNoteException; use App\Util\Exception\NotFoundException; use App\Util\Exception\RedirectException; +use App\Util\Exception\ServerException; use App\Util\Formatting; use Plugin\Repeat\Entity\NoteRepeat; use Symfony\Component\HttpFoundation\Request; @@ -47,7 +49,7 @@ class Repeat extends NoteHandlerPlugin * * @throws InvalidFormException * @throws NoSuchNoteException - * @throws RedirectException + * @throws RedirectException*@throws ClientException*@throws DuplicateFoundException * * @return bool Event hook */ @@ -58,17 +60,15 @@ class Repeat extends NoteHandlerPlugin } // If note is repeated, "is_repeated" is 1 - $opts = ['repeat_of' => $note->getId()]; + $is_repeat = DB::count('note_repeat', ['note_id' => $note->getId()]) >= 1; + try { - if (DB::findOneBy('note_repeat', $opts)) { + if (DB::findOneBy('note_repeat', ['repeat_of' => $note->getId()])) { return Event::next; } - } catch (DuplicateFoundException $e) { - } catch (NotFoundException $e) { + } catch (DuplicateFoundException|NotFoundException $e) { } - $is_repeat = DB::count('note_repeat', ['note_id' => $note->getId()]) >= 1; - // Generating URL for repeat action route $args = ['id' => $note->getId()]; $type = Router::ABSOLUTE_PATH; @@ -94,43 +94,47 @@ class Repeat extends NoteHandlerPlugin } /** - * @throws \App\Util\Exception\NoLoggedInUser + * Append on note information about user actions. + * + * @return array|bool */ - public function onAppendCardNote(array $vars, array &$result) { + public function onAppendCardNote(array $vars, array &$result) + { // if note is the original and user isn't the one who repeated, append on end "user repeated this" // if user is the one who repeated, append on end "you repeated this, remove repeat?" - $check_user = true; - try { - $user = Common::ensureLoggedIn(); - } catch (NoLoggedInUser $e) { - $check_user = false; - } + $check_user = !\is_null(Common::user()); $note = $vars['note']; $complementary_info = ''; - $repeat_actor = []; - $note_repeats = NoteRepeat::getNoteRepeats($note); + $repeat_actor = []; + $note_repeats = NoteRepeat::getNoteRepeats($note); // Get actors who replied foreach ($note_repeats as $reply) { $repeat_actor[] = Actor::getWithPK($reply->getActorId()); } - if (count($repeat_actor) < 1) { - return null; + if (\count($repeat_actor) < 1) { + return Event::next; } // Filter out multiple replies from the same actor - $repeat_actor = array_unique($repeat_actor, SORT_REGULAR); + $repeat_actor = array_unique($repeat_actor, \SORT_REGULAR); // Add to complementary info foreach ($repeat_actor as $actor) { - $repeat_actor_url = $actor->getUrl(); + $repeat_actor_url = $actor->getUrl(); $repeat_actor_nickname = $actor->getNickname(); if ($check_user && $actor->getId() === (Common::actor())->getId()) { // If the repeat is yours - $prepend = "You, " . ($prepend = &$complementary_info); + try { + $you_translation = _m('You'); + } catch (ServerException $e) { + $you_translation = 'You'; + } + + $prepend = "{$you_translation}, " . ($prepend = &$complementary_info); $complementary_info = $prepend; } else { // If the repeat is from someone else