diff options
Diffstat (limited to 'src/index.php')
-rw-r--r-- | src/index.php | 166 |
1 files changed, 153 insertions, 13 deletions
diff --git a/src/index.php b/src/index.php index 6258131..c75d112 100644 --- a/src/index.php +++ b/src/index.php @@ -1,5 +1,6 @@ <?php +use Gregwar\Captcha\CaptchaBuilder; use mystic\forum\Database; use mystic\forum\exceptions\DatabaseConnectionException; use mystic\forum\Messaging; @@ -14,12 +15,17 @@ use mystic\forum\utils\ValidationUtils; header_remove("X-Powered-By"); +if (($_SERVER["HTTP_USER_AGENT"] ?? "") === "") { + http_response_code(403); + exit; +} + // function exception_error_handler($errno, $errstr, $errfile, $errline ) { // throw new ErrorException(html_entity_decode($errstr), $errno, 0, $errfile, $errline); // } // set_error_handler("exception_error_handler"); -define("REGISTRATION_ENABLED", true); +define("REGISTRATION_ENABLED", isTrue(env("REGISTRATION_ENABLED") ?? "")); session_name("fsid"); session_start(); @@ -27,12 +33,21 @@ session_start(); const MAX_ATTACHMENT_SIZE = 0x200000; const MAX_ATTACHMENT_COUNT = 4; const THUMB_MAX_DIM = 100; +const CAPTCHA_PHRASE_LENGTH = 7; +const CAPTCHA_CHARSET = 'ABCDEFGHKLMNPQRTWXYZ234789abdefghkmnpqr'; $_rq_method = $_SERVER["REQUEST_METHOD"] ?? "GET"; $_action = $_GET["_action"] ?? null; $GLOBALS["action"] = $_action; +function generateCaptchaText(): string { + $phrase = ""; + for ($i = 0; $i < CAPTCHA_PHRASE_LENGTH; ++$i) + $phrase .= CAPTCHA_CHARSET[random_int(0, strlen(CAPTCHA_CHARSET) - 1)]; + return $phrase; +} + function _view(string $name, array $params = []): void { $___NAME = $name; $___PARAMS = &$params; @@ -42,13 +57,18 @@ function _view(string $name, array $params = []): void { echo "<!--{/" . htmlentities($name) . "}-->\n"; } +function isTrue(string $str): bool { + $str = strtolower($str); + return in_array($str, ["yes","true","y","t","on","enabled","1","?1"]); +} + function reArrayFiles(&$file_post) { $file_ary = []; $file_count = count($file_post['name']); $file_keys = array_keys($file_post); for ($i=0; $i<$file_count; $i++) { - if ($file_post["error"][$i] === UPLOAD_ERR_NO_FILE) + if ($file_post["error"][$i] !== UPLOAD_ERR_OK) continue; foreach ($file_keys as $key) { $file_ary[$i][$key] = $file_post[$key][$i]; @@ -93,6 +113,13 @@ function renderPost(string $contents): string { return $contents; } +function env(string $key): ?string { + $val = getenv($key); + if ($val === false) + return null; + return $val; +} + require_once __DIR__ . "/vendor/autoload.php"; $db = null; @@ -169,7 +196,7 @@ if ($_action === "auth") { RequestUtils::setAuthorizedUser($user); header("Location: " . $_GET["next"] ?? "."); } else { - _view("template_start", ["_title" => "Forum"]); + _view("template_start", ["_title" => "Log in"]); _view("template_navigation_start"); _view("template_navigation", ["user" => RequestUtils::getAuthorizedUser($db)]); _view("template_navigation_end"); @@ -189,11 +216,22 @@ if ($_action === "auth") { } if (RequestUtils::isRequestMethod("POST")) { - $username = RequestUtils::getRequiredField("username"); + $doNotFill = $_POST["username"] ?? null; + if ($doNotFill !== null) { + 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"); + + if ($captcha !== $_SESSION["captchaPhrase"]) { + RequestUtils::triggerFormError("Incorrect CAPTCHA text!"); + } // usernames are always lowercase $username = strtolower($username); @@ -250,7 +288,7 @@ if ($_action === "auth") { Messaging::html('<p>Please click <a href="?_action=auth">here</a> to log in!</p>'), ]); } else { - _view("template_start", ["_title" => "Forum"]); + _view("template_start", ["_title" => "Register"]); _view("template_navigation_start"); _view("template_navigation", ["user" => RequestUtils::getAuthorizedUser($db)]); _view("template_navigation_end"); @@ -302,6 +340,7 @@ if ($_action === "auth") { $post->content = $message; $post->postDate = new DateTimeImmutable(); $post->deleted = false; + $post->edited = false; $db->insert($post); @@ -335,7 +374,7 @@ if ($_action === "auth") { } } - _view("template_start", ["_title" => "Forum"]); + _view("template_start", ["_title" => $topic->title]); _view("template_navigation_start"); _view("template_navigation", ["user" => RequestUtils::getAuthorizedUser($db)]); _view("template_navigation_end"); @@ -383,6 +422,18 @@ if ($_action === "auth") { $title = trim(RequestUtils::getRequiredField("title")); $message = trim(RequestUtils::getRequiredField("message")); + $attachments = reArrayFiles($_FILES["files"]); + + if (count($attachments) > MAX_ATTACHMENT_COUNT) + RequestUtils::triggerFormError("Too many attachments"); + + // check all attachments before saving one + foreach ($attachments as $att) { + if ($att["size"] > MAX_ATTACHMENT_SIZE) { + RequestUtils::triggerFormError("Individual file size exceeded"); + } + } + if (strlen($title) < 1 || strlen($title) > 255) { RequestUtils::triggerFormError("Title too short or too long!"); } @@ -406,12 +457,29 @@ if ($_action === "auth") { $post->content = $message; $post->postDate = $topic->creationDate; $post->deleted = false; + $post->edited = false; $db->insert($post); + foreach ($attachments as $att) { + [ + "name" => $name, + "type" => $type, + "tmp_name" => $tmpName, + ] = $att; + $attachment = new Attachment(); + $attachment->id = $db->generateId(); + $attachment->name = $name; + $attachment->mimeType = $type; + $attachment->postId = $post->id; + $attachment->contents = file_get_contents($tmpName); + + $db->insert($attachment); + } + header("Location: ?_action=viewtopic&topic=" . urlencode($topic->id)); } else { - _view("template_start", ["_title" => "Forum"]); + _view("template_start", ["_title" => "New topic"]); _view("template_navigation_start"); _view("template_navigation", ["user" => RequestUtils::getAuthorizedUser($db)]); _view("template_navigation_end"); @@ -522,7 +590,7 @@ if ($_action === "auth") { continue; $topics[$post->topicId] = $topic; } - _view("template_start", ["_title" => "Forum"]); + _view("template_start", ["_title" => $user->displayName]); _view("template_navigation_start"); _view("template_navigation", ["user" => $currentUser]); _view("template_navigation_end"); @@ -549,12 +617,27 @@ if ($_action === "auth") { Messaging::error("No attachment exists with this id"); exit; } + + $name = preg_replace('/[\r\n\t\/]/', '_', $attachment->name); $extension = pathinfo($attachment->name, PATHINFO_EXTENSION); - header("Content-Type: " . FileUtils::getMimeTypeForExtension($extension)); + + $mime = FileUtils::getMimeTypeForExtension($extension); + switch ($mime) { + case "text/html": + case "text/css": + case "text/javascript": + case "text/xml": + case "application/css": + case "application/javascript": + case "application/xml": + $mime = "text/plain"; + break; + } + header("Content-Type: " . $mime); header("Content-Length: " . strlen($attachment->contents)); header("Cache-Control: no-cache"); - header("Content-Disposition: inline; filename=\"" . $attachment->name . "\""); + header("Content-Disposition: inline; filename=\"" . $name . "\""); echo $attachment->contents; } elseif ($_action === "profilepicture") { $userId = $_GET["user"] ?? throw new Exception("Missing user id"); @@ -722,7 +805,7 @@ if ($_action === "auth") { header("Location: ?_action=viewtopic&topic=" . urlencode($post->topicId)); } else { - _view("template_start", ["_title" => "Forum"]); + _view("template_start", ["_title" => "Delete post"]); _view("template_navigation_start"); _view("template_navigation", ["user" => RequestUtils::getAuthorizedUser($db)]); _view("template_navigation_end"); @@ -733,6 +816,54 @@ if ($_action === "auth") { ]); _view("template_end"); } +} elseif ($_action === "updatepost") { + RequestUtils::ensureRequestMethod("POST"); + + if (!$currentUser) { + http_response_code(403); + Messaging::error("You need to be logged in to update posts!"); + exit; + } + + $postId = RequestUtils::getRequiredField("post"); + $message = RequestUtils::getRequiredField("message"); + + $post = new Post(); + $post->id = $postId; + + if (!$db->fetch($post) || $post->deleted) { + http_response_code(404); + Messaging::error("No post exists with this id"); + exit; + } + + $topicAuthor = new User(); + $topicAuthor->id = $post->authorId; + + if (!$db->fetch($topicAuthor)) + $topicAuthor = null; + + $canEdit = ($currentUser->id === $topicAuthor?->id && $topicAuthor?->hasPermission(UserPermissions::EDIT_OWN_POST)) + || ($currentUser->hasPermission(UserPermissions::EDIT_OTHER_POST)); + + if (!$canEdit) { + http_response_code(403); + Messaging::error("You don't have permission to edit this post"); + exit; + } + + $confirm = $_POST["confirm"] ?? null; + + $post->content = $message; + $post->edited = true; + + if (!$db->update($post)) { + http_response_code(500); + Messaging::error("Failed to update post"); + exit; + } + + header("Location: ?_action=viewtopic&topic=" . urlencode($post->topicId) . "#post-" . urlencode($postId)); } elseif ($_action === "deletetopic") { RequestUtils::ensureRequestMethod("POST"); @@ -785,7 +916,7 @@ if ($_action === "auth") { header("Location: ."); } else { - _view("template_start", ["_title" => "Forum"]); + _view("template_start", ["_title" => "Delete topic"]); _view("template_navigation_start"); _view("template_navigation", ["user" => RequestUtils::getAuthorizedUser($db)]); _view("template_navigation_end"); @@ -840,8 +971,17 @@ if ($_action === "auth") { } header("Location: ./?_action=viewtopic&topic=" . urlencode($topicId)); +} elseif ($_action === "captcha") { + $phrase = generateCaptchaText(); + $builder = new CaptchaBuilder($phrase); + $builder->build(192, 48); + $_SESSION["captchaPhrase"] = $phrase; + header("Content-Type: image/jpeg"); + header("Pragma: no-cache"); + header("Cache-Control: no-cache"); + $builder->save(null, 40); } elseif ($_action === null) { - _view("template_start", ["_title" => "Forum"]); + _view("template_start"); _view("template_navigation_start"); _view("template_navigation", ["user" => RequestUtils::getAuthorizedUser($db)]); _view("template_navigation_end"); |