summaryrefslogtreecommitdiff
path: root/src/index.php
diff options
context:
space:
mode:
Diffstat (limited to 'src/index.php')
-rw-r--r--src/index.php261
1 files changed, 171 insertions, 90 deletions
diff --git a/src/index.php b/src/index.php
index f3a59b2..801cc07 100644
--- a/src/index.php
+++ b/src/index.php
@@ -18,6 +18,7 @@ use mystic\forum\utils\ValidationUtils;
use Symfony\Component\Mailer\Transport;
use Symfony\Component\Mime\Address;
use Symfony\Component\Mime\Email;
+use Symfony\Contracts\Service\Attribute\Required;
header_remove("X-Powered-By");
@@ -134,6 +135,9 @@ function reArrayFiles(&$file_post) {
}
function renderPost(string $contents): string {
+ $contents = preg_replace('~\R~u', "\n", $contents);
+ $contents = trim($contents);
+ $contents = preg_replace('/\n{3,}/', "\n\n", $contents);
$contents = htmlentities($contents);
$contents = nl2br($contents, false);
$lines = explode("\n", $contents);
@@ -220,8 +224,15 @@ $superuser->id = "SUPERUSER";
if (!$db->fetch($superuser)) {
$superUserPassword = base64_encode(random_bytes(12));
+ $suEmail = env("MYSTIC_FORUM_SUPERUSER_EMAIL");
+ if ($suEmail === null) {
+ http_response_code(500);
+ Messaging::error("No superuser email defined. Please set the 'MYSTIC_FORUM_SUPERUSER_EMAIL' environment variable accordingly");
+ exit;
+ }
+
$superuser->name = "superuser";
- $superuser->email = "";
+ $superuser->email = $suEmail;
$superuser->passwordHash = password_hash($superUserPassword, PASSWORD_DEFAULT);
$superuser->displayName = "SuperUser";
$superuser->created = new \DateTimeImmutable();
@@ -255,17 +266,18 @@ if ($_action === "auth") {
}
if (RequestUtils::isRequestMethod("POST")) {
- $username = RequestUtils::getRequiredField("username");
- $password = RequestUtils::getRequiredField("password");
+ $formId = "login";
+ $username = RequestUtils::getRequiredField("username", $formId);
+ $password = RequestUtils::getRequiredField("password", $formId);
$user = new User();
$user->name = $username;
if (!$db->fetchWhere($user, "name") || !password_verify($password, $user->passwordHash)) {
- RequestUtils::triggerFormError(__("Username or password incorrect!"));
+ RequestUtils::triggerFormError(__("Username or password incorrect!"), $formId);
}
if (!$user->activated) {
- RequestUtils::triggerFormError(__("Please activate your user account first!"));
+ RequestUtils::triggerFormError(__("Please activate your user account first!"), $formId);
}
RequestUtils::setAuthorizedUser($user);
@@ -291,40 +303,41 @@ if ($_action === "auth") {
}
if (RequestUtils::isRequestMethod("POST")) {
+ $formId = "register";
$doNotFill = $_POST["username"] ?? null;
if (!empty($doNotFill)) {
sleep(10);
http_response_code(204);
exit;
}
- $username = RequestUtils::getRequiredField("df82a9bc21");
- $password = RequestUtils::getRequiredField("password");
- $passwordRetype = RequestUtils::getRequiredField("password_retype");
- $email = trim(RequestUtils::getRequiredField("email"));
- $displayName = RequestUtils::getRequiredField("display_name");
- $captcha = RequestUtils::getRequiredField("captcha");
+ $username = RequestUtils::getRequiredField("df82a9bc21", $formId);
+ $password = RequestUtils::getRequiredField("password", $formId);
+ $passwordRetype = RequestUtils::getRequiredField("password_retype", $formId);
+ $email = trim(RequestUtils::getRequiredField("email", $formId));
+ $displayName = RequestUtils::getRequiredField("display_name", $formId);
+ $captcha = RequestUtils::getRequiredField("captcha", $formId);
if ($captcha !== ($_SESSION["captchaPhrase"] ?? null)) {
- RequestUtils::triggerFormError(__("Incorrect CAPTCHA text!"));
+ RequestUtils::triggerFormError(__("Incorrect CAPTCHA text!"), $formId);
}
// usernames are always lowercase
$username = strtolower($username);
if ($password !== $passwordRetype) {
- RequestUtils::triggerFormError(__("Passwords do not match!"));
+ RequestUtils::triggerFormError(__("Passwords do not match!"), $formId);
}
if (strlen($password) < 8) {
- RequestUtils::triggerFormError(__("Password too short! Your password must consist of 8 or more characters"));
+ RequestUtils::triggerFormError(__("Password too short! Your password must consist of 8 or more characters"), $formId);
}
if (!ValidationUtils::isUsernameValid($username)) {
- RequestUtils::triggerFormError(__("Username has an invalid format"));
+ RequestUtils::triggerFormError(__("Username has an invalid format"), $formId);
}
if (filter_var($email, FILTER_VALIDATE_EMAIL) === false) {
- RequestUtils::triggerFormError(__("Invalid email address"));
+ RequestUtils::triggerFormError(__("Invalid email address"), $formId);
}
$user = new User();
@@ -332,11 +345,11 @@ if ($_action === "auth") {
$user->email = $email;
if ($db->fetchWhere($user, "name")) {
- RequestUtils::triggerFormError(__("This username is already taken!"));
+ RequestUtils::triggerFormError(__("This username is already taken!"), $formId);
}
if ($db->fetchWhere($user, "email")) {
- RequestUtils::triggerFormError(__("This email address is already in use!"));
+ RequestUtils::triggerFormError(__("This email address is already in use!"), $formId);
}
// re-create user so we don't forget to clear properties set by the above queries
@@ -429,6 +442,7 @@ if ($_action === "auth") {
RequestUtils::unsetAuthorizedUser();
header("Location: " . ($_GET["next"] ?? "."));
} elseif ($_action === "viewtopic") {
+ $formId = "addpost";
$topicId = $_GET["topic"] ?? throw new Exception("Missing topic id");
$topic = new Topic();
$topic->id = $topicId;
@@ -448,19 +462,19 @@ if ($_action === "auth") {
$attachments = reArrayFiles($_FILES["files"]);
if (count($attachments) > MAX_ATTACHMENT_COUNT)
- RequestUtils::triggerFormError(__("Too many attachments"));
+ RequestUtils::triggerFormError(__("Too many attachments"), $formId);
// check all attachments before saving one
foreach ($attachments as $att) {
if ($att["size"] > MAX_ATTACHMENT_SIZE) {
- RequestUtils::triggerFormError(__("Individual file size exceeded"));
+ RequestUtils::triggerFormError(__("Individual file size exceeded"), $formId);
}
}
- $message = trim(RequestUtils::getRequiredField("message"));
+ $message = trim(RequestUtils::getRequiredField("message", $formId));
if (strlen($message) < 1 || strlen($message) > 0x8000) {
- RequestUtils::triggerFormError(__("Message too short or too long!"));
+ RequestUtils::triggerFormError(__("Message too short or too long!"), $formId);
}
$post = new Post();
@@ -552,27 +566,28 @@ if ($_action === "auth") {
}
if (RequestUtils::isRequestMethod("POST")) {
- $title = trim(RequestUtils::getRequiredField("title"));
- $message = trim(RequestUtils::getRequiredField("message"));
+ $formId = "newtopic";
+ $title = trim(RequestUtils::getRequiredField("title", $formId));
+ $message = trim(RequestUtils::getRequiredField("message", $formId));
$attachments = reArrayFiles($_FILES["files"]);
if (count($attachments) > MAX_ATTACHMENT_COUNT)
- RequestUtils::triggerFormError(__("Too many attachments"));
+ RequestUtils::triggerFormError(__("Too many attachments"), $formId);
// check all attachments before saving one
foreach ($attachments as $att) {
if ($att["size"] > MAX_ATTACHMENT_SIZE) {
- RequestUtils::triggerFormError(__("Individual file size exceeded"));
+ RequestUtils::triggerFormError(__("Individual file size exceeded"), $formId);
}
}
if (strlen($title) < 1 || strlen($title) > 255) {
- RequestUtils::triggerFormError(__("Title too short or too long!"));
+ RequestUtils::triggerFormError(__("Title too short or too long!"), $formId);
}
if (strlen($message) < 1 || strlen($message) > 0x8000) {
- RequestUtils::triggerFormError(__("Message too short or too long!"));
+ RequestUtils::triggerFormError(__("Message too short or too long!"), $formId);
}
$topic = new Topic();
@@ -653,64 +668,125 @@ if ($_action === "auth") {
}
if (RequestUtils::isRequestMethod("POST")) {
- $displayName = RequestUtils::getRequiredField("display_name");
- $pfpAction = RequestUtils::getRequiredField("pfp_action");
+ $formId = $_POST["form_id"] ?? null;
+ if ($formId === null) {
+ http_response_code(400);
+ msg_error("Missing form_id");
+ exit;
+ }
- $userName = $_POST["name"] ?? $user->name;
+ if ($formId === "update_password") {
+ if (!$currentUser) {
+ http_response_code(403);
+ msg_error(__("You must be logged in to update your password"));
+ exit;
+ }
- $user->displayName = $displayName;
+ if (!$isOwnProfile) {
+ RequestUtils::triggerFormError(__("You don't have permission to update this user's password"), $formId);
+ }
- $userName = strtolower($userName);
-
- if ($userName !== $user->name) {
- if ($lastNameChangeTooRecent) {
- RequestUtils::triggerFormError(__("You can only change your username every 30 days!"));
- } else {
- if (!ValidationUtils::isUsernameValid($userName))
- RequestUtils::triggerFormError(__("Invalid username!"));
- if (!ValidationUtils::isUsernameAvailable($db, $userName))
- RequestUtils::triggerFormError(__("This username is already taken!"));
- $user->name = $userName;
- $user->nameLastChanged = new DateTimeImmutable();
+ RequestUtils::ensureRequestMethod("POST");
+ $currentPassword = RequestUtils::getRequiredField("current_password", $formId);
+ $newPassword = RequestUtils::getRequiredField("new_password", $formId);
+ $retypePassword = RequestUtils::getRequiredField("retype_password", $formId);
+
+ if (!password_verify($currentPassword, $currentUser->passwordHash)) {
+ RequestUtils::triggerFormError(__("Current password is incorrect"), $formId);
+ }
+
+ if ($newPassword !== $retypePassword) {
+ RequestUtils::triggerFormError(__("New passwords don't match"), $formId);
+ }
+
+ if (strlen($newPassword) < 8) {
+ RequestUtils::triggerFormError(__("Password too short! Your password must consist of 8 or more characters"), $formId);
}
- }
- switch ($pfpAction) {
- case "keep":
- // Do nothing
- break;
- case "remove":
- $user->profilePicture = null;
- break;
- case "replace": {
- if (!isset($_FILES["pfp"]) || $_FILES["pfp"]["error"] !== UPLOAD_ERR_OK) {
- RequestUtils::triggerFormError(__("Please upload an image to change your profile picture"));
+ $currentUser->passwordHash = password_hash($newPassword, PASSWORD_DEFAULT);
+
+ if (!$db->update($currentUser)) {
+ RequestUtils::triggerFormError(__("Failed to update password"), $formId);
+ }
+
+ header("Location: $_SERVER[REQUEST_URI]");
+ } elseif ($formId === "update_profile") {
+ if (!$currentUser) {
+ http_response_code(403);
+ msg_error(__("You must be logged in to update your profile"));
+ exit;
+ }
+
+ $canEdit = ($currentUser?->id === $user?->id && $user?->hasPermission(UserPermissions::EDIT_OWN_USER))
+ || ($currentUser?->hasPermission(UserPermissions::EDIT_OTHER_USER));
+
+ if (!$canEdit) {
+ http_response_code(403);
+ msg_error(__("You don't have permission to update this profile"));
+ exit;
+ }
+
+ $displayName = RequestUtils::getRequiredField("display_name", $formId);
+ $pfpAction = RequestUtils::getRequiredField("pfp_action", $formId);
+
+ $userName = $_POST["name"] ?? $user->name;
+
+ $user->displayName = $displayName;
+
+ $userName = strtolower($userName);
+
+ if ($userName !== $user->name) {
+ if ($lastNameChangeTooRecent) {
+ RequestUtils::triggerFormError(__("You can only change your username every 30 days!"), $formId);
+ } else {
+ if (!ValidationUtils::isUsernameValid($userName))
+ RequestUtils::triggerFormError(__("Invalid username!"), $formId);
+ if (!ValidationUtils::isUsernameAvailable($db, $userName))
+ RequestUtils::triggerFormError(__("This username is already taken!"), $formId);
+ $user->name = $userName;
+ $user->nameLastChanged = new DateTimeImmutable();
}
- $im = @imagecreatefromjpeg($_FILES["pfp"]["tmp_name"]);
- if ($im === false)
- $im = @imagecreatefrompng($_FILES["pfp"]["tmp_name"]);
- if ($im === false)
- RequestUtils::triggerFormError(__("Please upload a valid PNG or JPEG file"));
- /** @var \GdImage $im */
- $thumb = imagecreatetruecolor(64, 64);
- imagecopyresampled($thumb, $im, 0, 0, 0, 0, 64, 64, imagesx($im), imagesy($im));
- imagedestroy($im);
- $stream = fopen("php://memory", "w+");
- imagejpeg($thumb, $stream, 50);
- rewind($stream);
- imagedestroy($thumb);
- $user->profilePicture = stream_get_contents($stream);
- fclose($stream);
- } break;
- default:
- RequestUtils::triggerFormError("Invalid value for pfp_action");
- break;
- }
+ }
- if (!$db->update($user))
- RequestUtils::triggerFormError(__("Failed to save changes", context: "Update profile"));
+ switch ($pfpAction) {
+ case "keep":
+ // Do nothing
+ break;
+ case "remove":
+ $user->profilePicture = null;
+ break;
+ case "replace": {
+ if (!isset($_FILES["pfp"]) || $_FILES["pfp"]["error"] !== UPLOAD_ERR_OK) {
+ RequestUtils::triggerFormError(__("Please upload an image to change your profile picture"), $formId);
+ }
+ $im = @imagecreatefromjpeg($_FILES["pfp"]["tmp_name"]);
+ if ($im === false)
+ $im = @imagecreatefrompng($_FILES["pfp"]["tmp_name"]);
+ if ($im === false)
+ RequestUtils::triggerFormError(__("Please upload a valid PNG or JPEG file"), $formId);
+ /** @var \GdImage $im */
+ $thumb = imagecreatetruecolor(64, 64);
+ imagecopyresampled($thumb, $im, 0, 0, 0, 0, 64, 64, imagesx($im), imagesy($im));
+ imagedestroy($im);
+ $stream = fopen("php://memory", "w+");
+ imagejpeg($thumb, $stream, 50);
+ rewind($stream);
+ imagedestroy($thumb);
+ $user->profilePicture = stream_get_contents($stream);
+ fclose($stream);
+ } break;
+ default:
+ RequestUtils::triggerFormError("Invalid value for pfp_action", $formId);
+ break;
+ }
+
+ if (!$db->update($user))
+ RequestUtils::triggerFormError(__("Failed to save changes", context: "Update profile"), $formId);
- header("Location: $_SERVER[REQUEST_URI]");
+ header("Location: $_SERVER[REQUEST_URI]");
+ } else {
+ msg_error("Invalid formId");
+ }
} else {
$posts = $db->fetchCustom(Post::class, 'WHERE author_id = $1 ORDER BY post_date DESC', [ $userId ]);
$topics = [];
@@ -727,7 +803,10 @@ if ($_action === "auth") {
}
_view("template_start", ["_title" => $user->displayName]);
_view("template_navigation_start");
- _view("template_navigation", ["user" => $currentUser]);
+ _view("template_navigation", [
+ "user" => $currentUser,
+ "isViewingOwnProfile" => $isOwnProfile,
+ ]);
_view("template_navigation_end");
_view("view_user", [
"user" => $user,
@@ -915,8 +994,8 @@ if ($_action === "auth") {
msg_error("You need to be logged in to delete posts!");
exit;
}
-
- $postId = RequestUtils::getRequiredField("post");
+ $formId = "deletepost";
+ $postId = RequestUtils::getRequiredField("post", $formId);
$post = new Post();
$post->id = $postId;
@@ -993,8 +1072,9 @@ if ($_action === "auth") {
exit;
}
- $postId = RequestUtils::getRequiredField("post");
- $message = RequestUtils::getRequiredField("message");
+ $formId = "updatepost";
+ $postId = RequestUtils::getRequiredField("post", $formId);
+ $message = RequestUtils::getRequiredField("message", $formId);
$post = new Post();
$post->id = $postId;
@@ -1041,7 +1121,8 @@ if ($_action === "auth") {
exit;
}
- $topicId = RequestUtils::getRequiredField("topic");
+ $formId = "deletetopic";
+ $topicId = RequestUtils::getRequiredField("topic", $formId);
$topic = new Topic();
$topic->id = $topicId;
@@ -1103,8 +1184,9 @@ if ($_action === "auth") {
exit;
}
- $topicId = RequestUtils::getRequiredField("topic");
- $title = RequestUtils::getRequiredField("title");
+ $formId = "updatetopic";
+ $topicId = RequestUtils::getRequiredField("topic", $formId);
+ $title = RequestUtils::getRequiredField("title", $formId);
$topic = new Topic();
$topic->id = $topicId;
@@ -1140,11 +1222,10 @@ if ($_action === "auth") {
header("Location: ./?_action=viewtopic&topic=" . urlencode($topicId));
} elseif ($_action === "search") {
- if (RequestUtils::isRequestMethod("POST")) {
- $query = RequestUtils::getRequiredField("query");
- /** @var Post[] $posts */
-
+ $query = $_GET["query"] ?? null;
+ if ($query !== null) {
$start_time = microtime(true);
+ /** @var Post[] $posts */
$posts = $db->execCustomQuery(<<<SQL
SELECT posts.* FROM topics, posts
WHERE