[core] fix permissions in forum and notes

This includes preventing silent failures when permission is denied, preventing unauthorized users from being shown the note edit form, patching typos, and extracting NOTES_REQUEST to its own permission
This commit is contained in:
discomrade 2024-02-21 11:13:09 +00:00 committed by Shish
parent ac86cb1302
commit aff227ac31
6 changed files with 59 additions and 76 deletions

View file

@ -125,6 +125,7 @@ abstract class Permissions
public const NOTES_ADMIN = "notes_admin"; public const NOTES_ADMIN = "notes_admin";
public const NOTES_CREATE = "notes_create"; public const NOTES_CREATE = "notes_create";
public const NOTES_EDIT = "notes_edit"; public const NOTES_EDIT = "notes_edit";
public const NOTES_REQUEST = "notes_request";
public const POOLS_ADMIN = "pools_admin"; public const POOLS_ADMIN = "pools_admin";
public const POOLS_CREATE = "pools_create"; public const POOLS_CREATE = "pools_create";

View file

@ -119,6 +119,7 @@ new UserClass("user", "base", [
Permissions::FORUM_CREATE => true, Permissions::FORUM_CREATE => true,
Permissions::NOTES_CREATE => true, Permissions::NOTES_CREATE => true,
Permissions::NOTES_EDIT => true, Permissions::NOTES_EDIT => true,
Permissions::NOTES_REQUEST => true,
Permissions::POOLS_CREATE => true, Permissions::POOLS_CREATE => true,
Permissions::POOLS_UPDATE => true, Permissions::POOLS_UPDATE => true,
]); ]);

View file

@ -102,7 +102,7 @@ class Forum extends Extension
if ($event->page_matches("forum/index", paged: true)) { if ($event->page_matches("forum/index", paged: true)) {
$pageNumber = $event->get_iarg('page_num', 1) - 1; $pageNumber = $event->get_iarg('page_num', 1) - 1;
$this->show_last_threads($page, $pageNumber, $user->can(Permissions::FORUM_ADMIN)); $this->show_last_threads($page, $pageNumber, $user->can(Permissions::FORUM_ADMIN));
if (!$user->can(Permissions::FORUM_CREATE)) { if ($user->can(Permissions::FORUM_CREATE)) {
$this->theme->display_new_thread_composer($page); $this->theme->display_new_thread_composer($page);
} }
} }
@ -119,62 +119,51 @@ class Forum extends Extension
if ($user->can(Permissions::FORUM_ADMIN)) { if ($user->can(Permissions::FORUM_ADMIN)) {
$this->theme->add_actions_block($page, $threadID); $this->theme->add_actions_block($page, $threadID);
} }
if (!$user->can(Permissions::FORUM_CREATE)) { if ($user->can(Permissions::FORUM_CREATE)) {
$this->theme->display_new_post_composer($page, $threadID); $this->theme->display_new_post_composer($page, $threadID);
} }
} }
if ($event->page_matches("forum/new")) { if ($event->page_matches("forum/new", permission: Permissions::FORUM_CREATE)) {
$this->theme->display_new_thread_composer($page); $this->theme->display_new_thread_composer($page);
} }
if ($event->page_matches("forum/create")) { if ($event->page_matches("forum/create", permission: Permissions::FORUM_CREATE)) {
$redirectTo = "forum/index"; $errors = $this->sanity_check_new_thread();
if (!$user->can(Permissions::FORUM_CREATE)) {
$errors = $this->sanity_check_new_thread();
if (count($errors) > 0) { if (count($errors) > 0) {
throw new InvalidInput(implode("<br>", $errors)); throw new InvalidInput(implode("<br>", $errors));
}
$newThreadID = $this->save_new_thread($user);
$this->save_new_post($newThreadID, $user);
$redirectTo = "forum/view/" . $newThreadID . "/1";
} }
$newThreadID = $this->save_new_thread($user);
$this->save_new_post($newThreadID, $user);
$redirectTo = "forum/view/" . $newThreadID . "/1";
$page->set_mode(PageMode::REDIRECT); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link($redirectTo)); $page->set_redirect(make_link($redirectTo));
} }
if ($event->page_matches("forum/delete/{threadID}/{postID}")) { if ($event->page_matches("forum/delete/{threadID}/{postID}", permission: Permissions::FORUM_ADMIN)) {
$threadID = $event->get_iarg('threadID'); $threadID = $event->get_iarg('threadID');
$postID = $event->get_iarg('postID'); $postID = $event->get_iarg('postID');
$this->delete_post($postID);
if ($user->can(Permissions::FORUM_ADMIN)) {
$this->delete_post($postID);
}
$page->set_mode(PageMode::REDIRECT); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("forum/view/" . $threadID)); $page->set_redirect(make_link("forum/view/" . $threadID));
} }
if ($event->page_matches("forum/nuke/{threadID}")) { if ($event->page_matches("forum/nuke/{threadID}", permission: Permissions::FORUM_ADMIN)) {
$threadID = $event->get_iarg('threadID'); $threadID = $event->get_iarg('threadID');
$this->delete_thread($threadID);
if ($user->can(Permissions::FORUM_ADMIN)) {
$this->delete_thread($threadID);
}
$page->set_mode(PageMode::REDIRECT); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("forum/index")); $page->set_redirect(make_link("forum/index"));
} }
if ($event->page_matches("forum/answer")) { if ($event->page_matches("forum/answer", permission: Permissions::FORUM_CREATE)) {
$threadID = int_escape($event->req_POST("threadID")); $threadID = int_escape($event->req_POST("threadID"));
$total_pages = $this->get_total_pages_for_thread($threadID); $total_pages = $this->get_total_pages_for_thread($threadID);
if (!$user->can(Permissions::FORUM_CREATE)) {
$errors = $this->sanity_check_new_post();
if (count($errors) > 0) { $errors = $this->sanity_check_new_post();
throw new InvalidInput(implode("<br>", $errors));
} if (count($errors) > 0) {
$this->save_new_post($threadID, $user); throw new InvalidInput(implode("<br>", $errors));
} }
$this->save_new_post($threadID, $user);
$page->set_mode(PageMode::REDIRECT); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("forum/view/" . $threadID . "/" . $total_pages)); $page->set_redirect(make_link("forum/view/" . $threadID . "/" . $total_pages));
} }

View file

@ -90,61 +90,46 @@ class Notes extends Extension
if ($event->page_matches("note/history/{note_id}", paged: true)) { if ($event->page_matches("note/history/{note_id}", paged: true)) {
$this->get_history($event->get_iarg('note_id'), $event->get_iarg('page_num', 1) - 1); $this->get_history($event->get_iarg('note_id'), $event->get_iarg('page_num', 1) - 1);
} }
if ($event->page_matches("note/revert/{noteID}/{reviewID}")) { if ($event->page_matches("note/revert/{noteID}/{reviewID}", permission: Permissions::NOTES_EDIT)) {
$noteID = $event->get_iarg('noteID'); $noteID = $event->get_iarg('noteID');
$reviewID = $event->get_iarg('reviewID'); $reviewID = $event->get_iarg('reviewID');
if (!$user->is_anonymous()) { $this->revert_history($noteID, $reviewID);
$this->revert_history($noteID, $reviewID);
}
$page->set_mode(PageMode::REDIRECT); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("note/updated")); $page->set_redirect(make_link("note/updated"));
} }
if ($event->page_matches("note/add_request")) { if ($event->page_matches("note/add_request", permission: Permissions::NOTES_REQUEST)) {
$image_id = int_escape($event->req_POST("image_id")); $image_id = int_escape($event->req_POST("image_id"));
if (!$user->is_anonymous()) { $this->add_note_request($image_id);
$this->add_note_request($image_id);
}
$page->set_mode(PageMode::REDIRECT); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("post/view/$image_id")); $page->set_redirect(make_link("post/view/$image_id"));
} }
if ($event->page_matches("note/nuke_requests")) { if ($event->page_matches("note/nuke_requests", permission: Permissions::NOTES_ADMIN)) {
$image_id = int_escape($event->req_POST("image_id")); $image_id = int_escape($event->req_POST("image_id"));
if ($user->can(Permissions::NOTES_ADMIN)) { $this->nuke_requests($image_id);
$this->nuke_requests($image_id);
}
$page->set_mode(PageMode::REDIRECT); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("post/view/$image_id")); $page->set_redirect(make_link("post/view/$image_id"));
} }
if ($event->page_matches("note/create_note")) { if ($event->page_matches("note/create_note", permission: Permissions::NOTES_CREATE)) {
$page->set_mode(PageMode::DATA); $page->set_mode(PageMode::DATA);
if (!$user->can(Permissions::NOTES_CREATE)) { $note_id = $this->add_new_note();
$note_id = $this->add_new_note(); $page->set_data(\Safe\json_encode([
$page->set_data(\Safe\json_encode([ 'status' => 'success',
'status' => 'success', 'note_id' => $note_id,
'note_id' => $note_id, ]));
]));
}
} }
if ($event->page_matches("note/update_note")) { if ($event->page_matches("note/update_note", permission: Permissions::NOTES_EDIT)) {
$page->set_mode(PageMode::DATA); $page->set_mode(PageMode::DATA);
if (!$user->can(Permissions::NOTES_EDIT)) { $this->update_note();
$this->update_note(); $page->set_data(\Safe\json_encode(['status' => 'success']));
$page->set_data(\Safe\json_encode(['status' => 'success']));
}
} }
if ($event->page_matches("note/delete_note")) { if ($event->page_matches("note/delete_note", permission: Permissions::NOTES_ADMIN)) {
$page->set_mode(PageMode::DATA); $page->set_mode(PageMode::DATA);
if ($user->can(Permissions::NOTES_ADMIN)) { $this->delete_note();
$this->delete_note(); $page->set_data(\Safe\json_encode(['status' => 'success']));
$page->set_data(\Safe\json_encode(['status' => 'success']));
}
} }
if ($event->page_matches("note/nuke_notes")) { if ($event->page_matches("note/nuke_notes", permission: Permissions::NOTES_ADMIN)) {
$image_id = int_escape($event->req_POST("image_id")); $image_id = int_escape($event->req_POST("image_id"));
if ($user->can(Permissions::NOTES_ADMIN)) { $this->nuke_notes($image_id);
$this->nuke_notes($image_id);
}
$page->set_mode(PageMode::REDIRECT); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("post/view/$image_id")); $page->set_redirect(make_link("post/view/$image_id"));
} }
@ -160,7 +145,7 @@ class Notes extends Extension
//display form on image event //display form on image event
$notes = $this->get_notes($event->image->id); $notes = $this->get_notes($event->image->id);
$this->theme->display_note_system($page, $event->image->id, $notes, $user->can(Permissions::NOTES_ADMIN)); $this->theme->display_note_system($page, $event->image->id, $notes, $user->can(Permissions::NOTES_ADMIN), $user->can(Permissions::NOTES_EDIT));
} }
@ -170,14 +155,17 @@ class Notes extends Extension
public function onImageAdminBlockBuilding(ImageAdminBlockBuildingEvent $event): void public function onImageAdminBlockBuilding(ImageAdminBlockBuildingEvent $event): void
{ {
global $user; global $user;
if (!$user->can(Permissions::NOTES_CREATE)) { if ($user->can(Permissions::NOTES_CREATE)) {
$event->add_part($this->theme->note_button($event->image->id)); $event->add_part($this->theme->note_button($event->image->id));
$event->add_part($this->theme->request_button($event->image->id));
if ($user->can(Permissions::NOTES_ADMIN)) { if ($user->can(Permissions::NOTES_ADMIN)) {
$event->add_part($this->theme->nuke_notes_button($event->image->id)); $event->add_part($this->theme->nuke_notes_button($event->image->id));
$event->add_part($this->theme->nuke_requests_button($event->image->id)); $event->add_part($this->theme->nuke_requests_button($event->image->id));
} }
} }
if ($user->can(Permissions::NOTES_REQUEST)) {
$event->add_part($this->theme->request_button($event->image->id));
}
} }

View file

@ -48,10 +48,13 @@ function renderNotes() {
noteDiv.style.height = note.height * scale + 'px'; noteDiv.style.height = note.height * scale + 'px';
let text = document.createElement('div'); let text = document.createElement('div');
text.innerText = note.note; text.innerText = note.note;
noteDiv.addEventListener('click', (e) => { // only add listener if user has edit permissions
noteBeingEdited = note.note_id; if (window.notes_edit) {
renderNotes(); noteDiv.addEventListener('click', (e) => {
}); noteBeingEdited = note.note_id;
renderNotes();
});
}
noteDiv.appendChild(text); noteDiv.appendChild(text);
notesContainer.appendChild(noteDiv); notesContainer.appendChild(noteDiv);

View file

@ -47,7 +47,7 @@ class NotesTheme extends Themelet
/** /**
* @param Note[] $recovered_notes * @param Note[] $recovered_notes
*/ */
public function display_note_system(Page $page, int $image_id, array $recovered_notes, bool $adminOptions): void public function display_note_system(Page $page, int $image_id, array $recovered_notes, bool $adminOptions, bool $editOptions): void
{ {
$to_json = []; $to_json = [];
foreach ($recovered_notes as $note) { foreach ($recovered_notes as $note) {
@ -65,6 +65,7 @@ class NotesTheme extends Themelet
window.notes = ".\Safe\json_encode($to_json)."; window.notes = ".\Safe\json_encode($to_json).";
window.notes_image_id = $image_id; window.notes_image_id = $image_id;
window.notes_admin = ".($adminOptions ? "true" : "false")."; window.notes_admin = ".($adminOptions ? "true" : "false").";
window.notes_edit = ".($editOptions ? "true" : "false").";
</script>"); </script>");
} }