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"); |