From 16a7e204412a392b0239600cd56c541841a75aca Mon Sep 17 00:00:00 2001 From: flashwave <me@flash.moe> Date: Fri, 28 Mar 2025 20:19:54 +0000 Subject: [PATCH] Logging cleanup. --- public-legacy/auth/password.php | 2 +- public-legacy/manage/changelog/change.php | 6 +- public-legacy/manage/changelog/tag.php | 6 +- public-legacy/manage/forum/redirs.php | 4 +- public-legacy/manage/general/emoticon.php | 4 +- public-legacy/manage/general/emoticons.php | 6 +- public-legacy/manage/general/logs.php | 4 +- .../manage/general/setting-delete.php | 2 +- public-legacy/manage/general/setting.php | 2 +- public-legacy/manage/news/category.php | 6 +- public-legacy/manage/news/post.php | 6 +- public-legacy/manage/users/ban.php | 4 +- public-legacy/manage/users/note.php | 6 +- public-legacy/manage/users/role.php | 4 +- public-legacy/manage/users/user.php | 2 +- public-legacy/manage/users/warning.php | 4 +- public-legacy/settings/account.php | 4 +- public-legacy/settings/data.php | 2 +- public-legacy/settings/logs.php | 4 +- public-legacy/settings/sessions.php | 4 +- public/index.php | 100 ++++++++++-------- src/Forum/ForumPostsRoutes.php | 56 ++++------ src/Forum/ForumTopicsRoutes.php | 52 ++------- .../AuditLogInfo.php => Logs/LogInfo.php} | 8 +- src/Logs/LogsContext.php | 60 +++++++++++ .../AuditLogData.php => Logs/LogsData.php} | 53 +++++----- src/MisuzuContext.php | 22 +--- 27 files changed, 220 insertions(+), 213 deletions(-) rename src/{AuditLog/AuditLogInfo.php => Logs/LogInfo.php} (97%) create mode 100644 src/Logs/LogsContext.php rename src/{AuditLog/AuditLogData.php => Logs/LogsData.php} (74%) diff --git a/public-legacy/auth/password.php b/public-legacy/auth/password.php index 7090bbe8..7dc85aa8 100644 --- a/public-legacy/auth/password.php +++ b/public-legacy/auth/password.php @@ -71,7 +71,7 @@ while($canResetPassword) { $msz->usersCtx->passwords->updateUserPassword($userInfo, $passwordNew); $msz->usersCtx->totps->deleteUserTotp($userInfo); - $msz->createAuditLog('PASSWORD_RESET', [], $userInfo); + $msz->logsCtx->createUserLog($userInfo, 'PASSWORD_RESET'); $msz->authCtx->recoveryTokens->invalidateToken($tokenInfo); diff --git a/public-legacy/manage/changelog/change.php b/public-legacy/manage/changelog/change.php index 1b31f76a..2b5e8313 100644 --- a/public-legacy/manage/changelog/change.php +++ b/public-legacy/manage/changelog/change.php @@ -38,7 +38,7 @@ if($_SERVER['REQUEST_METHOD'] === 'GET' && !empty($_GET['delete'])) { Template::throwError(403); $msz->changelog->deleteChange($changeInfo); - $msz->createAuditLog('CHANGELOG_ENTRY_DELETE', [$changeInfo->id]); + $msz->logsCtx->createAuthedLog('CHANGELOG_ENTRY_DELETE', [$changeInfo->id]); Tools::redirect($msz->urls->format('manage-changelog-changes')); return; } @@ -100,9 +100,9 @@ while($_SERVER['REQUEST_METHOD'] === 'POST' && CSRF::validateRequest()) { } } - $msz->createAuditLog( + $msz->logsCtx->createAuthedLog( $isNew ? 'CHANGELOG_ENTRY_CREATE' : 'CHANGELOG_ENTRY_EDIT', - [$changeInfo->id] + [$changeInfo->id], ); Tools::redirect($msz->urls->format('manage-changelog-change', ['change' => $changeInfo->id])); diff --git a/public-legacy/manage/changelog/tag.php b/public-legacy/manage/changelog/tag.php index 1361e9de..75c96574 100644 --- a/public-legacy/manage/changelog/tag.php +++ b/public-legacy/manage/changelog/tag.php @@ -27,7 +27,7 @@ if($_SERVER['REQUEST_METHOD'] === 'GET' && !empty($_GET['delete'])) { Template::throwError(403); $msz->changelog->deleteTag($tagInfo); - $msz->createAuditLog('CHANGELOG_TAG_DELETE', [$tagInfo->id]); + $msz->logsCtx->createAuthedLog('CHANGELOG_TAG_DELETE', [$tagInfo->id]); Tools::redirect($msz->urls->format('manage-changelog-tags')); return; } @@ -51,9 +51,9 @@ while($_SERVER['REQUEST_METHOD'] === 'POST' && CSRF::validateRequest()) { $msz->changelog->updateTag($tagInfo, $name, $description, $archive); } - $msz->createAuditLog( + $msz->logsCtx->createAuthedLog( $isNew ? 'CHANGELOG_TAG_CREATE' : 'CHANGELOG_TAG_EDIT', - [$tagInfo->id] + [$tagInfo->id], ); if($isNew) { diff --git a/public-legacy/manage/forum/redirs.php b/public-legacy/manage/forum/redirs.php index 6e6f12cd..c0d380cd 100644 --- a/public-legacy/manage/forum/redirs.php +++ b/public-legacy/manage/forum/redirs.php @@ -14,7 +14,7 @@ if($_SERVER['REQUEST_METHOD'] === 'POST') { $rTopicId = !empty($_POST['topic_redir_id']) && is_scalar($_POST['topic_redir_id']) ? trim((string)$_POST['topic_redir_id']) : ''; $rTopicURL = !empty($_POST['topic_redir_url']) && is_scalar($_POST['topic_redir_url']) ? trim((string)$_POST['topic_redir_url']) : ''; - $msz->createAuditLog('FORUM_TOPIC_REDIR_CREATE', [$rTopicId]); + $msz->logsCtx->createAuthedLog('FORUM_TOPIC_REDIR_CREATE', [$rTopicId]); $msz->forumCtx->topicRedirects->createTopicRedirect($rTopicId, $msz->authInfo->userInfo, $rTopicURL); Tools::redirect($msz->urls->format('manage-forum-topic-redirs')); return; @@ -25,7 +25,7 @@ if(!empty($_GET['m']) && $_GET['m'] === 'explode') { throw new \Exception("Request verification failed."); $rTopicId = !empty($_GET['t']) && is_scalar($_GET['t']) ? (string)$_GET['t'] : ''; - $msz->createAuditLog('FORUM_TOPIC_REDIR_REMOVE', [$rTopicId]); + $msz->logsCtx->createAuthedLog('FORUM_TOPIC_REDIR_REMOVE', [$rTopicId]); $msz->forumCtx->topicRedirects->deleteTopicRedirect($rTopicId); Tools::redirect($msz->urls->format('manage-forum-topic-redirs')); return; diff --git a/public-legacy/manage/general/emoticon.php b/public-legacy/manage/general/emoticon.php index 479e3f57..16e8e540 100644 --- a/public-legacy/manage/general/emoticon.php +++ b/public-legacy/manage/general/emoticon.php @@ -94,9 +94,9 @@ while($_SERVER['REQUEST_METHOD'] === 'POST' && CSRF::validateRequest()) { $sCurrent[] = $string; } - $msz->createAuditLog( + $msz->logsCtx->createAuthedLog( $isNew ? 'EMOTICON_CREATE' : 'EMOTICON_EDIT', - [$emoteInfo->id] + [$emoteInfo->id], ); Tools::redirect($msz->urls->format('manage-general-emoticon', ['emote' => $emoteInfo->id])); diff --git a/public-legacy/manage/general/emoticons.php b/public-legacy/manage/general/emoticons.php index 548a94a0..d670c583 100644 --- a/public-legacy/manage/general/emoticons.php +++ b/public-legacy/manage/general/emoticons.php @@ -20,20 +20,20 @@ if(CSRF::validateRequest() && !empty($_GET['emote'])) { if(!empty($_GET['delete'])) { $msz->emotesCtx->emotes->deleteEmote($emoteInfo); - $msz->createAuditLog('EMOTICON_DELETE', [$emoteInfo->id]); + $msz->logsCtx->createAuthedLog('EMOTICON_DELETE', [$emoteInfo->id]); } else { if(isset($_GET['order'])) { $order = !empty($_GET['order']) && is_scalar($_GET['order']) ? (string)$_GET['order'] : ''; $offset = $order === 'i' ? 10 : ($order === 'd' ? -10 : 0); $msz->emotesCtx->emotes->updateEmoteOrderOffset($emoteInfo, $offset); - $msz->createAuditLog('EMOTICON_ORDER', [$emoteInfo->id]); + $msz->logsCtx->createAuthedLog('EMOTICON_ORDER', [$emoteInfo->id]); } if(isset($_GET['alias'])) { $alias = !empty($_GET['alias']) && is_scalar($_GET['alias']) ? (string)$_GET['alias'] : ''; if($msz->emotesCtx->emotes->checkEmoteString($alias) === '') { $msz->emotesCtx->emotes->addEmoteString($emoteInfo, $alias); - $msz->createAuditLog('EMOTICON_ALIAS', [$emoteInfo->id, $alias]); + $msz->logsCtx->createAuthedLog('EMOTICON_ALIAS', [$emoteInfo->id, $alias]); } } } diff --git a/public-legacy/manage/general/logs.php b/public-legacy/manage/general/logs.php index 12c3abaa..bc0c4bbb 100644 --- a/public-legacy/manage/general/logs.php +++ b/public-legacy/manage/general/logs.php @@ -9,11 +9,11 @@ if(!isset($msz) || !($msz instanceof \Misuzu\MisuzuContext)) if(!$msz->authInfo->getPerms('global')->check(Perm::G_LOGS_VIEW)) Template::throwError(403); -$pagination = Pagination::fromInput($msz->auditLog->countLogs(), 50); +$pagination = Pagination::fromInput($msz->logsCtx->logs->countLogs(), 50); if(!$pagination->validOffset) Template::throwError(404); -$logs = iterator_to_array($msz->auditLog->getLogs(pagination: $pagination)); +$logs = iterator_to_array($msz->logsCtx->logs->getLogs(pagination: $pagination)); $userInfos = []; $userColours = []; diff --git a/public-legacy/manage/general/setting-delete.php b/public-legacy/manage/general/setting-delete.php index 0a5a8205..796e046f 100644 --- a/public-legacy/manage/general/setting-delete.php +++ b/public-legacy/manage/general/setting-delete.php @@ -12,7 +12,7 @@ if($valueInfo === null) Template::throwError(404); if($_SERVER['REQUEST_METHOD'] === 'POST' && CSRF::validateRequest()) { - $msz->createAuditLog('CONFIG_DELETE', [$valueInfo->name]); + $msz->logsCtx->createAuthedLog('CONFIG_DELETE', [$valueInfo->name]); $msz->config->removeValues($valueInfo->name); Tools::redirect($msz->urls->format('manage-general-settings')); return; diff --git a/public-legacy/manage/general/setting.php b/public-legacy/manage/general/setting.php index 15aca438..116c9464 100644 --- a/public-legacy/manage/general/setting.php +++ b/public-legacy/manage/general/setting.php @@ -74,7 +74,7 @@ while($_SERVER['REQUEST_METHOD'] === 'POST' && CSRF::validateRequest()) { $applyFunc = $msz->config->setString(...); } - $msz->createAuditLog($isNew ? 'CONFIG_CREATE' : 'CONFIG_UPDATE', [$sName]); + $msz->logsCtx->createAuthedLog($isNew ? 'CONFIG_CREATE' : 'CONFIG_UPDATE', [$sName]); $applyFunc($sName, $sValue); Tools::redirect($msz->urls->format('manage-general-settings')); return; diff --git a/public-legacy/manage/news/category.php b/public-legacy/manage/news/category.php index 8a64f33d..4a848eea 100644 --- a/public-legacy/manage/news/category.php +++ b/public-legacy/manage/news/category.php @@ -27,7 +27,7 @@ if($_SERVER['REQUEST_METHOD'] === 'GET' && !empty($_GET['delete'])) { Template::throwError(403); $msz->news->deleteCategory($categoryInfo); - $msz->createAuditLog('NEWS_CATEGORY_DELETE', [$categoryInfo->id]); + $msz->logsCtx->createAuthedLog('NEWS_CATEGORY_DELETE', [$categoryInfo->id]); Tools::redirect($msz->urls->format('manage-news-categories')); return; } @@ -51,9 +51,9 @@ while($_SERVER['REQUEST_METHOD'] === 'POST' && CSRF::validateRequest()) { $msz->news->updateCategory($categoryInfo, $name, $description, $hidden); } - $msz->createAuditLog( + $msz->logsCtx->createAuthedLog( $isNew ? 'NEWS_CATEGORY_CREATE' : 'NEWS_CATEGORY_EDIT', - [$categoryInfo->id] + [$categoryInfo->id], ); if($isNew) { diff --git a/public-legacy/manage/news/post.php b/public-legacy/manage/news/post.php index bea405af..783ce36f 100644 --- a/public-legacy/manage/news/post.php +++ b/public-legacy/manage/news/post.php @@ -28,7 +28,7 @@ if($_SERVER['REQUEST_METHOD'] === 'GET' && !empty($_GET['delete'])) { Template::throwError(403); $msz->news->deletePost($postInfo); - $msz->createAuditLog('NEWS_POST_DELETE', [$postInfo->id]); + $msz->logsCtx->createAuthedLog('NEWS_POST_DELETE', [$postInfo->id]); Tools::redirect($msz->urls->format('manage-news-posts')); return; } @@ -55,9 +55,9 @@ while($_SERVER['REQUEST_METHOD'] === 'POST' && CSRF::validateRequest()) { $msz->news->updatePost($postInfo, $category, $title, $body, $featured); } - $msz->createAuditLog( + $msz->logsCtx->createAuthedLog( $isNew ? 'NEWS_POST_CREATE' : 'NEWS_POST_EDIT', - [$postInfo->id] + [$postInfo->id], ); if($isNew && $postInfo->featured) { diff --git a/public-legacy/manage/users/ban.php b/public-legacy/manage/users/ban.php index 1a2d05a5..5a4e4675 100644 --- a/public-legacy/manage/users/ban.php +++ b/public-legacy/manage/users/ban.php @@ -22,7 +22,7 @@ if($_SERVER['REQUEST_METHOD'] === 'GET' && !empty($_GET['delete'])) { } $msz->usersCtx->bans->deleteBans($banInfo); - $msz->createAuditLog('BAN_DELETE', [$banInfo->id, $banInfo->userId]); + $msz->logsCtx->createAuthedLog('BAN_DELETE', [$banInfo->id, $banInfo->userId]); Tools::redirect($msz->urls->format('manage-users-bans', ['user' => $banInfo->userId])); return; } @@ -67,7 +67,7 @@ while($_SERVER['REQUEST_METHOD'] === 'POST' && CSRF::validateRequest()) { severity: $severity, modInfo: $modInfo ); - $msz->createAuditLog('BAN_CREATE', [$banInfo->id, $userInfo->id]); + $msz->logsCtx->createAuthedLog('BAN_CREATE', [$banInfo->id, $userInfo->id]); Tools::redirect($msz->urls->format('manage-users-bans', ['user' => $userInfo->id])); return; } diff --git a/public-legacy/manage/users/note.php b/public-legacy/manage/users/note.php index 0f8a3009..d72d4afd 100644 --- a/public-legacy/manage/users/note.php +++ b/public-legacy/manage/users/note.php @@ -39,7 +39,7 @@ if($hasUserId) { Template::throwError(403); $msz->usersCtx->modNotes->deleteNotes($noteInfo); - $msz->createAuditLog('MOD_NOTE_DELETE', [$noteInfo->id, $noteInfo->userId]); + $msz->logsCtx->createAuthedLog('MOD_NOTE_DELETE', [$noteInfo->id, $noteInfo->userId]); Tools::redirect($msz->urls->format('manage-users-notes', ['user' => $noteInfo->userId])); return; } @@ -64,9 +64,9 @@ while($_SERVER['REQUEST_METHOD'] === 'POST' && CSRF::validateRequest()) { $msz->usersCtx->modNotes->updateNote($noteInfo, $title, $body); } - $msz->createAuditLog( + $msz->logsCtx->createAuthedLog( $isNew ? 'MOD_NOTE_CREATE' : 'MOD_NOTE_UPDATE', - [$noteInfo->id, $userInfo->id] + [$noteInfo->id, $userInfo->id], ); // this is easier diff --git a/public-legacy/manage/users/role.php b/public-legacy/manage/users/role.php index 28e7bf39..d0abf2cb 100644 --- a/public-legacy/manage/users/role.php +++ b/public-legacy/manage/users/role.php @@ -148,9 +148,9 @@ while($_SERVER['REQUEST_METHOD'] === 'POST' && CSRF::validateRequest()) { ); } - $msz->createAuditLog( + $msz->logsCtx->createAuthedLog( $isNew ? 'ROLE_CREATE' : 'ROLE_UPDATE', - [$roleInfo->id] + [$roleInfo->id], ); if($canEditPerms) { diff --git a/public-legacy/manage/users/user.php b/public-legacy/manage/users/user.php index b6a7a90e..a6402cdc 100644 --- a/public-legacy/manage/users/user.php +++ b/public-legacy/manage/users/user.php @@ -62,7 +62,7 @@ if(CSRF::validateRequest() && $canEdit) { } if($allowToImpersonate) { - $msz->createAuditLog('USER_IMPERSONATE', [$userInfo->id, $userInfo->name]); + $msz->logsCtx->createAuthedLog('USER_IMPERSONATE', [$userInfo->id, $userInfo->name]); $tokenBuilder = $msz->authInfo->tokenInfo->toBuilder(); $tokenBuilder->setImpersonatedUserId($userInfo->id); diff --git a/public-legacy/manage/users/warning.php b/public-legacy/manage/users/warning.php index dfac1df1..0cfa810e 100644 --- a/public-legacy/manage/users/warning.php +++ b/public-legacy/manage/users/warning.php @@ -20,7 +20,7 @@ if($_SERVER['REQUEST_METHOD'] === 'GET' && !empty($_GET['delete'])) { } $msz->usersCtx->warnings->deleteWarnings($warnInfo); - $msz->createAuditLog('WARN_DELETE', [$warnInfo->id, $warnInfo->userId]); + $msz->logsCtx->createAuthedLog('WARN_DELETE', [$warnInfo->id, $warnInfo->userId]); Tools::redirect($msz->urls->format('manage-users-warnings', ['user' => $warnInfo->userId])); return; } @@ -41,7 +41,7 @@ while($_SERVER['REQUEST_METHOD'] === 'POST' && CSRF::validateRequest()) { $userInfo, $body, modInfo: $modInfo ); - $msz->createAuditLog('WARN_CREATE', [$warnInfo->id, $userInfo->id]); + $msz->logsCtx->createAuthedLog('WARN_CREATE', [$warnInfo->id, $userInfo->id]); Tools::redirect($msz->urls->format('manage-users-warnings', ['user' => $userInfo->id])); return; } diff --git a/public-legacy/settings/account.php b/public-legacy/settings/account.php index 98a4e7d7..74a0472a 100644 --- a/public-legacy/settings/account.php +++ b/public-legacy/settings/account.php @@ -90,7 +90,7 @@ if($isVerifiedRequest && !empty($_POST['current_password'])) { $errors[] = $msz->usersCtx->users->validateEMailAddressText($checkMail); } else { $msz->usersCtx->users->updateUser(userInfo: $userInfo, emailAddr: $_POST['email']['new']); - $msz->createAuditLog('PERSONAL_EMAIL_CHANGE', [$_POST['email']['new']]); + $msz->logsCtx->createAuthedLog('PERSONAL_EMAIL_CHANGE', [$_POST['email']['new']]); } } } @@ -106,7 +106,7 @@ if($isVerifiedRequest && !empty($_POST['current_password'])) { $errors[] = UserPasswordsData::validateUserPasswordText($checkPassword); } else { $msz->usersCtx->passwords->updateUserPassword($userInfo, $_POST['password']['new']); - $msz->createAuditLog('PERSONAL_PASSWORD_CHANGE'); + $msz->logsCtx->createAuthedLog('PERSONAL_PASSWORD_CHANGE'); } } } diff --git a/public-legacy/settings/data.php b/public-legacy/settings/data.php index cc805eb8..04b280f1 100644 --- a/public-legacy/settings/data.php +++ b/public-legacy/settings/data.php @@ -116,7 +116,7 @@ if(isset($_POST['action']) && is_string($_POST['action'])) { && ($msz->usersCtx->passwords->getUserPassword($userInfo)?->verifyPassword($_POST['password'] ?? ''))) { switch($_POST['action']) { case 'data': - $msz->createAuditLog('PERSONAL_DATA_DOWNLOAD'); + $msz->logsCtx->createAuthedLog('PERSONAL_DATA_DOWNLOAD'); $timeStamp = floor(time() / 3600) * 3600; $fileName = sprintf('msz-user-data-%d-%d.zip', $userInfo->id, $timeStamp); diff --git a/public-legacy/settings/logs.php b/public-legacy/settings/logs.php index 82f34f64..58ea08fd 100644 --- a/public-legacy/settings/logs.php +++ b/public-legacy/settings/logs.php @@ -11,10 +11,10 @@ if($currentUser === null) Template::throwError(401); $loginHistoryPagination = Pagination::fromInput($msz->authCtx->loginAttempts->countAttempts(userInfo: $currentUser), 5, 'hp'); -$accountLogPagination = Pagination::fromInput($msz->auditLog->countLogs(userInfo: $currentUser), 10, 'ap'); +$accountLogPagination = Pagination::fromInput($msz->logsCtx->logs->countLogs(userInfo: $currentUser), 10, 'ap'); $loginHistory = iterator_to_array($msz->authCtx->loginAttempts->getAttempts(userInfo: $currentUser, pagination: $loginHistoryPagination)); -$auditLogs = iterator_to_array($msz->auditLog->getLogs(userInfo: $currentUser, pagination: $accountLogPagination)); +$auditLogs = iterator_to_array($msz->logsCtx->logs->getLogs(userInfo: $currentUser, pagination: $accountLogPagination)); Template::render('settings.logs', [ 'login_history_list' => $loginHistory, diff --git a/public-legacy/settings/sessions.php b/public-legacy/settings/sessions.php index 90be2cd1..43a90f26 100644 --- a/public-legacy/settings/sessions.php +++ b/public-legacy/settings/sessions.php @@ -20,7 +20,7 @@ while($_SERVER['REQUEST_METHOD'] === 'POST' && CSRF::validateRequest()) { if($sessionId === 'all') { $activeSessionKilled = true; $msz->authCtx->sessions->deleteSessions(userInfos: $currentUser); - $msz->createAuditLog('PERSONAL_SESSION_DESTROY_ALL'); + $msz->logsCtx->createAuthedLog('PERSONAL_SESSION_DESTROY_ALL'); } else { try { $sessionInfo = $msz->authCtx->sessions->getSession(sessionId: $sessionId); @@ -33,7 +33,7 @@ while($_SERVER['REQUEST_METHOD'] === 'POST' && CSRF::validateRequest()) { $activeSessionKilled = $sessionInfo->id === $activeSessionId; $msz->authCtx->sessions->deleteSessions(sessionInfos: $sessionInfo); - $msz->createAuditLog('PERSONAL_SESSION_DESTROY', [$sessionInfo->id]); + $msz->logsCtx->createAuthedLog('PERSONAL_SESSION_DESTROY', [$sessionInfo->id]); } if($activeSessionKilled) { diff --git a/public/index.php b/public/index.php index 6afe51d8..289fb614 100644 --- a/public/index.php +++ b/public/index.php @@ -5,6 +5,8 @@ use RuntimeException; use Index\MediaType; use Index\Http\Content\MultipartFormContent; use Index\Http\Content\Multipart\ValueMultipartFormData; +use Index\Http\Routing\Router; +use Index\Http\Routing\Routes\RouteInfo; use Misuzu\Auth\{AuthTokenBuilder,AuthTokenCookie,AuthTokenInfo}; require_once __DIR__ . '/../misuzu.php'; @@ -115,51 +117,6 @@ $router = $msz->createRouting($request); $msz->startTemplating(); if($msz->domainRoles->hasRole($request->getHeaderLine('Host'), 'main')) { - // Reconstruct $_POST since PHP no longer makes it for us - if($request->getBody()->isReadable() && empty($_POST)) { - $mszRequestContent = (function($contentType, $stream) { - if($contentType->equals('application/x-www-form-urlencoded')) { - parse_str((string)$stream, $postVars); - return $postVars; - } - - if($contentType->equals('multipart/form-data')) - try { - return MultipartFormContent::parseStream($stream, $contentType->boundary); - } catch(RuntimeException $ex) {} - - return null; - })(MediaType::parse($request->getHeaderLine('Content-Type')), $request->getBody()); - - $_POST = (function($requestContent) { - if(is_array($requestContent)) - return $requestContent; - - if($requestContent instanceof MultipartFormContent) { - $postVars = []; - foreach($requestContent->params as $name => $values) { - if(count($values) === 0) - $postVars[$name] = ''; - elseif(count($values) === 1) - $postVars[$name] = $values[0] instanceof ValueMultipartFormData ? (string)$values[0] : ''; - else { - $postVar = []; - foreach($values as $value) - $postVars[] = $value instanceof ValueMultipartFormData ? (string)$value : ''; - - $postVars[$name] = $postVar; - } - } - - return $postVars; - } - - return []; - })($mszRequestContent); - - $_REQUEST = array_merge($_GET, $_POST); - } - $mszRequestPath = substr($request->requestTarget, 1); $mszLegacyPathPrefix = Misuzu::PATH_PUBLIC_LEGACY . '/'; $mszLegacyPath = $mszLegacyPathPrefix . $mszRequestPath; @@ -167,6 +124,14 @@ if($msz->domainRoles->hasRole($request->getHeaderLine('Host'), 'main')) { if(str_starts_with($mszLegacyPath, $mszLegacyPathPrefix)) { $mszLegacyPathReal = realpath($mszLegacyPath); if($mszLegacyPath === $mszLegacyPathReal || $mszLegacyPath === $mszLegacyPathReal . '/') { + // this is here so filters can run... + $router->router->route(RouteInfo::exact($request->method, $request->requestTarget, function() {})); + $response = $router->router->handle($request); + if($response->getBody()->getSize() > 0) { + Router::output($response); + exit; + } + if(str_starts_with($mszRequestPath, 'manage') && !$msz->hasManageAccess()) Template::throwError(403); @@ -174,6 +139,51 @@ if($msz->domainRoles->hasRole($request->getHeaderLine('Host'), 'main')) { $mszLegacyPath .= '/index.php'; if(is_file($mszLegacyPath)) { + // Reconstruct $_POST since PHP no longer makes it for us + if($request->getBody()->isReadable() && empty($_POST)) { + $mszRequestContent = (function($contentType, $stream) { + if($contentType->equals('application/x-www-form-urlencoded')) { + parse_str((string)$stream, $postVars); + return $postVars; + } + + if($contentType->equals('multipart/form-data')) + try { + return MultipartFormContent::parseStream($stream, $contentType->boundary); + } catch(RuntimeException $ex) {} + + return null; + })(MediaType::parse($request->getHeaderLine('Content-Type')), $request->getBody()); + + $_POST = (function($requestContent) { + if(is_array($requestContent)) + return $requestContent; + + if($requestContent instanceof MultipartFormContent) { + $postVars = []; + foreach($requestContent->params as $name => $values) { + if(count($values) === 0) + $postVars[$name] = ''; + elseif(count($values) === 1) + $postVars[$name] = $values[0] instanceof ValueMultipartFormData ? (string)$values[0] : ''; + else { + $postVar = []; + foreach($values as $value) + $postVars[] = $value instanceof ValueMultipartFormData ? (string)$value : ''; + + $postVars[$name] = $postVar; + } + } + + return $postVars; + } + + return []; + })($mszRequestContent); + + $_REQUEST = array_merge($_GET, $_POST); + } + require_once $mszLegacyPath; return; } diff --git a/src/Forum/ForumPostsRoutes.php b/src/Forum/ForumPostsRoutes.php index 077db87e..0080374e 100644 --- a/src/Forum/ForumPostsRoutes.php +++ b/src/Forum/ForumPostsRoutes.php @@ -7,8 +7,8 @@ use Index\Http\Routing\{RouteHandler,RouteHandlerCommon}; use Index\Http\Routing\Routes\PatternRoute; use Index\Urls\{UrlFormat,UrlRegistry,UrlSource,UrlSourceCommon}; use Misuzu\{CSRF,Perm}; -use Misuzu\AuditLog\AuditLogData; use Misuzu\Auth\AuthInfo; +use Misuzu\Logs\LogsContext; use Misuzu\Users\UsersContext; class ForumPostsRoutes implements RouteHandler, UrlSource { @@ -16,9 +16,9 @@ class ForumPostsRoutes implements RouteHandler, UrlSource { public function __construct( private UrlRegistry $urls, - private ForumContext $forum, + private ForumContext $forumCtx, private UsersContext $usersCtx, - private AuditLogData $auditLog, + private LogsContext $logsCtx, private AuthInfo $authInfo, ) {} @@ -26,7 +26,7 @@ class ForumPostsRoutes implements RouteHandler, UrlSource { #[UrlFormat('forum-post', '/forum/posts/<post>')] public function getPost(HttpResponseBuilder $response, HttpRequest $request, string $postId): mixed { try { - $post = $this->forum->posts->getPost(postId: $postId); + $post = $this->forumCtx->posts->getPost(postId: $postId); } catch(RuntimeException $ex) { return 404; } @@ -39,7 +39,7 @@ class ForumPostsRoutes implements RouteHandler, UrlSource { if($post->deleted && !$canDeleteAny) return 404; - $postsCount = $this->forum->posts->countPosts( + $postsCount = $this->forumCtx->posts->countPosts( topicInfo: $post->topicId, upToPostInfo: $post, deleted: $canDeleteAny ? null : false @@ -76,7 +76,7 @@ class ForumPostsRoutes implements RouteHandler, UrlSource { } try { - $post = $this->forum->posts->getPost( + $post = $this->forumCtx->posts->getPost( postId: $postId, deleted: false, ); @@ -102,7 +102,7 @@ class ForumPostsRoutes implements RouteHandler, UrlSource { } if(!$perms->check(Perm::F_POST_DELETE_ANY)) { - $topic = $this->forum->topics->getTopic(postInfo: $post); + $topic = $this->forumCtx->topics->getTopic(postInfo: $post); if($topic->deleted) { $response->statusCode = 404; return [ @@ -156,7 +156,7 @@ class ForumPostsRoutes implements RouteHandler, UrlSource { } } - $originalPost = $this->forum->posts->getPost(topicInfo: $post->topicId); + $originalPost = $this->forumCtx->posts->getPost(topicInfo: $post->topicId); if($originalPost->id === $post->id) { $response->statusCode = 403; return [ @@ -167,7 +167,7 @@ class ForumPostsRoutes implements RouteHandler, UrlSource { ]; } - $category = $this->forum->categories->getCategory(postInfo: $post); + $category = $this->forumCtx->categories->getCategory(postInfo: $post); if($category->archived) { $response->statusCode = 400; return [ @@ -178,14 +178,8 @@ class ForumPostsRoutes implements RouteHandler, UrlSource { ]; } - $this->forum->posts->deletePost($post); - $this->auditLog->createLog( - $this->authInfo->userInfo, - 'FORUM_POST_DELETE', - [$post->id], - $request->remoteAddress, - $request->countryCode - ); + $this->forumCtx->posts->deletePost($post); + $this->logsCtx->createAuthedLog('FORUM_POST_DELETE', [$post->id]); return 204; } @@ -211,7 +205,7 @@ class ForumPostsRoutes implements RouteHandler, UrlSource { } try { - $post = $this->forum->posts->getPost( + $post = $this->forumCtx->posts->getPost( postId: $postId, deleted: true, ); @@ -247,7 +241,7 @@ class ForumPostsRoutes implements RouteHandler, UrlSource { ]; } - $category = $this->forum->categories->getCategory(postInfo: $post); + $category = $this->forumCtx->categories->getCategory(postInfo: $post); if($category->archived) { $response->statusCode = 400; return [ @@ -258,14 +252,8 @@ class ForumPostsRoutes implements RouteHandler, UrlSource { ]; } - $this->forum->posts->nukePost($post); - $this->auditLog->createLog( - $this->authInfo->userInfo, - 'FORUM_POST_NUKE', - [$post->id], - $request->remoteAddress, - $request->countryCode - ); + $this->forumCtx->posts->nukePost($post); + $this->logsCtx->createAuthedLog('FORUM_POST_NUKE', [$post->id]); return 204; } @@ -291,7 +279,7 @@ class ForumPostsRoutes implements RouteHandler, UrlSource { } try { - $post = $this->forum->posts->getPost( + $post = $this->forumCtx->posts->getPost( postId: $postId, deleted: true, ); @@ -327,7 +315,7 @@ class ForumPostsRoutes implements RouteHandler, UrlSource { ]; } - $category = $this->forum->categories->getCategory(postInfo: $post); + $category = $this->forumCtx->categories->getCategory(postInfo: $post); if($category->archived) { $response->statusCode = 400; return [ @@ -338,14 +326,8 @@ class ForumPostsRoutes implements RouteHandler, UrlSource { ]; } - $this->forum->posts->restorePost($post); - $this->auditLog->createLog( - $this->authInfo->userInfo, - 'FORUM_POST_RESTORE', - [$post->id], - $request->remoteAddress, - $request->countryCode - ); + $this->forumCtx->posts->restorePost($post); + $this->logsCtx->createAuthedLog('FORUM_POST_RESTORE', [$post->id]); return 204; } diff --git a/src/Forum/ForumTopicsRoutes.php b/src/Forum/ForumTopicsRoutes.php index 1643a144..f87ffe56 100644 --- a/src/Forum/ForumTopicsRoutes.php +++ b/src/Forum/ForumTopicsRoutes.php @@ -9,8 +9,8 @@ use Index\Http\Routing\{RouteHandler,RouteHandlerCommon}; use Index\Http\Routing\Routes\PatternRoute; use Index\Urls\{UrlFormat,UrlRegistry,UrlSource,UrlSourceCommon}; use Misuzu\{CSRF,Pagination,Perm,Template}; -use Misuzu\AuditLog\AuditLogData; use Misuzu\Auth\AuthInfo; +use Misuzu\Logs\LogsContext; use Misuzu\Users\UsersContext; class ForumTopicsRoutes implements RouteHandler, UrlSource { @@ -19,7 +19,7 @@ class ForumTopicsRoutes implements RouteHandler, UrlSource { public function __construct( private ForumContext $forumCtx, private UsersContext $usersCtx, - private AuditLogData $auditLog, + private LogsContext $logsCtx, private AuthInfo $authInfo, ) {} @@ -263,13 +263,7 @@ class ForumTopicsRoutes implements RouteHandler, UrlSource { } $this->forumCtx->topics->deleteTopic($topic); - $this->auditLog->createLog( - $this->authInfo->userInfo, - 'FORUM_TOPIC_DELETE', - [$topic->id], - $request->remoteAddress, - $request->countryCode - ); + $this->logsCtx->createAuthedLog('FORUM_TOPIC_DELETE', [$topic->id]); return 204; } @@ -343,13 +337,7 @@ class ForumTopicsRoutes implements RouteHandler, UrlSource { } $this->forumCtx->topics->restoreTopic($topic); - $this->auditLog->createLog( - $this->authInfo->userInfo, - 'FORUM_TOPIC_RESTORE', - [$topic->id], - $request->remoteAddress, - $request->countryCode - ); + $this->logsCtx->createAuthedLog('FORUM_TOPIC_RESTORE', [$topic->id]); return 204; } @@ -423,13 +411,7 @@ class ForumTopicsRoutes implements RouteHandler, UrlSource { } $this->forumCtx->topics->nukeTopic($topic); - $this->auditLog->createLog( - $this->authInfo->userInfo, - 'FORUM_TOPIC_NUKE', - [$topic->id], - $request->remoteAddress, - $request->countryCode - ); + $this->logsCtx->createAuthedLog('FORUM_TOPIC_NUKE', [$topic->id]); return 204; } @@ -503,13 +485,7 @@ class ForumTopicsRoutes implements RouteHandler, UrlSource { } $this->forumCtx->topics->bumpTopic($topic); - $this->auditLog->createLog( - $this->authInfo->userInfo, - 'FORUM_TOPIC_BUMP', - [$topic->id], - $request->remoteAddress, - $request->countryCode - ); + $this->logsCtx->createAuthedLog('FORUM_TOPIC_BUMP', [$topic->id]); return 204; } @@ -593,13 +569,7 @@ class ForumTopicsRoutes implements RouteHandler, UrlSource { } $this->forumCtx->topics->lockTopic($topic); - $this->auditLog->createLog( - $this->authInfo->userInfo, - 'FORUM_TOPIC_LOCK', - [$topic->id], - $request->remoteAddress, - $request->countryCode - ); + $this->logsCtx->createAuthedLog('FORUM_TOPIC_LOCK', [$topic->id]); return 204; } @@ -683,13 +653,7 @@ class ForumTopicsRoutes implements RouteHandler, UrlSource { } $this->forumCtx->topics->unlockTopic($topic); - $this->auditLog->createLog( - $this->authInfo->userInfo, - 'FORUM_TOPIC_UNLOCK', - [$topic->id], - $request->remoteAddress, - $request->countryCode - ); + $this->logsCtx->createAuthedLog('FORUM_TOPIC_UNLOCK', [$topic->id]); return 204; } diff --git a/src/AuditLog/AuditLogInfo.php b/src/Logs/LogInfo.php similarity index 97% rename from src/AuditLog/AuditLogInfo.php rename to src/Logs/LogInfo.php index 9f01a988..883fb002 100644 --- a/src/AuditLog/AuditLogInfo.php +++ b/src/Logs/LogInfo.php @@ -1,11 +1,11 @@ <?php -namespace Misuzu\AuditLog; +namespace Misuzu\Logs; use ValueError; use Carbon\CarbonImmutable; use Index\Db\DbResult; -class AuditLogInfo { +class LogInfo { /** @param scalar[] $params */ public function __construct( public private(set) string $id, @@ -17,8 +17,8 @@ class AuditLogInfo { public private(set) string $countryCode, ) {} - public static function fromResult(DbResult $result): AuditLogInfo { - return new AuditLogInfo( + public static function fromResult(DbResult $result): LogInfo { + return new LogInfo( id: $result->getString(0), userId: $result->getStringOrNull(1), action: $result->getString(2), diff --git a/src/Logs/LogsContext.php b/src/Logs/LogsContext.php new file mode 100644 index 00000000..ddbf9d3f --- /dev/null +++ b/src/Logs/LogsContext.php @@ -0,0 +1,60 @@ +<?php +namespace Misuzu\Logs; + +use Index\Db\DbConnection; +use Index\Http\HttpRequest; +use Index\Http\Routing\{RouteHandler,RouteHandlerCommon}; +use Index\Http\Routing\Filters\PrefixFilter; +use Misuzu\Auth\AuthInfo; +use Misuzu\Users\UserInfo; + +class LogsContext implements RouteHandler { + use RouteHandlerCommon; + + public private(set) LogsData $logs; + + private ?HttpRequest $request = null; + + public function __construct( + DbConnection $dbConn, + private AuthInfo $authInfo, + ) { + $this->logs = new LogsData($dbConn); + } + + #[PrefixFilter('/')] + public function filterRequest(HttpRequest $request): void { + $this->request = $request; + } + + /** @param mixed[] $params */ + public function createSystemLog(string $action, array $params = []): void { + $this->logs->createLog(null, $action, $params, null, 'XS'); + } + + /** @param mixed[] $params */ + public function createAuthedLog(string $action, array $params = []): void { + $this->logs->createLog( + $this->authInfo->userInfo, + $action, + $params, + $this->request?->remoteAddress, + $this->request->countryCode ?? 'XX', + ); + } + + /** @param mixed[] $params */ + public function createUserLog( + UserInfo|string|null $userInfo, + string $action, + array $params = [], + ): void { + $this->logs->createLog( + $userInfo, + $action, + $params, + $this->request?->remoteAddress, + $this->request->countryCode ?? 'XX', + ); + } +} diff --git a/src/AuditLog/AuditLogData.php b/src/Logs/LogsData.php similarity index 74% rename from src/AuditLog/AuditLogData.php rename to src/Logs/LogsData.php index 791b3ad7..c1c62453 100644 --- a/src/AuditLog/AuditLogData.php +++ b/src/Logs/LogsData.php @@ -1,12 +1,12 @@ <?php -namespace Misuzu\AuditLog; +namespace Misuzu\Logs; use InvalidArgumentException; use Index\Db\{DbConnection,DbStatementCache}; use Misuzu\Pagination; use Misuzu\Users\UserInfo; -class AuditLogData { +class LogsData { private DbStatementCache $cache; public function __construct(DbConnection $dbConn) { @@ -15,13 +15,13 @@ class AuditLogData { public function countLogs( UserInfo|string|null $userInfo = null, - ?string $remoteAddr = null + string|null|false $remoteAddress = false, ): int { if($userInfo instanceof UserInfo) $userInfo = $userInfo->id; $hasUserInfo = $userInfo !== null; - $hasRemoteAddr = $remoteAddr !== null; + $hasRemoteAddr = $remoteAddress !== false; $args = 0; $query = 'SELECT COUNT(*) FROM msz_audit_log'; @@ -29,17 +29,19 @@ class AuditLogData { ++$args; $query .= ' WHERE user_id = ?'; } - if($hasRemoteAddr) { - $query .= (++$args > 1 ? ' AND' : ' WHERE'); - $query .= ' log_remote_addr = INET6_ATON(?)'; - } + if($remoteAddress !== false) + $query .= sprintf( + ' %s log_remote_addr %s', + ++$args > 1 ? ' AND' : ' WHERE', + $remoteAddress === null ? 'IS NULL' : '= INET6_ATON(?)' + ); $stmt = $this->cache->get($query); if($hasUserInfo) $stmt->nextParameter($userInfo); - if($hasRemoteAddr) - $stmt->nextParameter($remoteAddr); + if(is_string($remoteAddress)) + $stmt->nextParameter($remoteAddress); $stmt->execute(); $result = $stmt->getResult(); @@ -51,17 +53,16 @@ class AuditLogData { return $count; } - /** @return \Iterator<int, AuditLogInfo> */ + /** @return \Iterator<int, LogInfo> */ public function getLogs( UserInfo|string|null $userInfo = null, - ?string $remoteAddr = null, + string|null|false $remoteAddress = false, ?Pagination $pagination = null ): iterable { if($userInfo instanceof UserInfo) $userInfo = $userInfo->id; $hasUserInfo = $userInfo !== null; - $hasRemoteAddr = $remoteAddr !== null; $hasPagination = $pagination !== null; $args = 0; @@ -76,10 +77,12 @@ class AuditLogData { ++$args; $query .= ' WHERE user_id = ?'; } - if($hasRemoteAddr) { - $query .= (++$args > 1 ? ' AND' : ' WHERE'); - $query .= ' log_remote_addr = INET6_ATON(?)'; - } + if($remoteAddress !== false) + $query .= sprintf( + ' %s log_remote_addr %s', + ++$args > 1 ? ' AND' : ' WHERE', + $remoteAddress === null ? 'IS NULL' : '= INET6_ATON(?)' + ); $query .= ' ORDER BY log_created DESC'; if($hasPagination) $query .= ' LIMIT ? OFFSET ?'; @@ -88,14 +91,14 @@ class AuditLogData { if($hasUserInfo) $stmt->nextParameter($userInfo); - if($hasRemoteAddr) - $stmt->nextParameter($remoteAddr); + if(is_string($remoteAddress)) + $stmt->nextParameter($remoteAddress); if($hasPagination) $pagination->addToStatement($stmt); $stmt->execute(); - return $stmt->getResultIterator(AuditLogInfo::fromResult(...)); + return $stmt->getResultIterator(LogInfo::fromResult(...)); } /** @param mixed[] $params */ @@ -103,9 +106,9 @@ class AuditLogData { UserInfo|string|null $userInfo, string $action, array $params = [], - string $remoteAddr = '::1', - string $countryCode = 'XX' - ): void { + ?string $remoteAddress = null, + string $countryCode = 'XX', + ): string { if($userInfo instanceof UserInfo) $userInfo = $userInfo->id; @@ -131,8 +134,10 @@ class AuditLogData { $stmt->nextParameter($userInfo); $stmt->nextParameter($action); $stmt->nextParameter($params); - $stmt->nextParameter($remoteAddr); + $stmt->nextParameter($remoteAddress); $stmt->nextParameter($countryCode); $stmt->execute(); + + return (string)$stmt->lastInsertId; } } diff --git a/src/MisuzuContext.php b/src/MisuzuContext.php index 35fa6e49..6b1e3d58 100644 --- a/src/MisuzuContext.php +++ b/src/MisuzuContext.php @@ -24,10 +24,8 @@ class MisuzuContext { public private(set) BinarySnowflake $sfBinary; public private(set) RandomSnowflake $sfRandom; - public private(set) AuditLog\AuditLogData $auditLog; - public private(set) Counters\CountersData $counters; - public private(set) Changelog\ChangelogData $changelog; + public private(set) Counters\CountersData $counters; public private(set) News\NewsData $news; public private(set) DatabaseContext $dbCtx; @@ -37,6 +35,7 @@ class MisuzuContext { public private(set) Comments\CommentsContext $commentsCtx; public private(set) Emoticons\EmotesContext $emotesCtx; public private(set) Forum\ForumContext $forumCtx; + public private(set) Logs\LogsContext $logsCtx; public private(set) Messages\MessagesContext $messagesCtx; public private(set) OAuth2\OAuth2Context $oauth2Ctx; public private(set) Profile\ProfileContext $profileCtx; @@ -101,6 +100,7 @@ class MisuzuContext { Forum\ForumContext::class, config: $this->config->scopeTo('forum'), )); + $this->deps->register($this->logsCtx = $this->deps->constructLazy(Logs\LogsContext::class)); $this->deps->register($this->messagesCtx = $this->deps->constructLazy( Messages\MessagesContext::class, config: $this->config->scopeTo('messages'), @@ -116,7 +116,6 @@ class MisuzuContext { config: $this->config->scopeTo('redirects'), )); - $this->deps->register($this->auditLog = $this->deps->constructLazy(AuditLog\AuditLogData::class)); $this->deps->register($this->changelog = $this->deps->constructLazy(Changelog\ChangelogData::class)); $this->deps->register($this->counters = $this->deps->constructLazy(Counters\CountersData::class)); $this->deps->register($this->news = $this->deps->constructLazy(News\NewsData::class)); @@ -132,20 +131,6 @@ class MisuzuContext { Mailer::init($this->config->scopeTo('mail')); } - /** @param mixed[] $params */ - public function createAuditLog(string $action, array $params = [], UserInfo|string|null $userInfo = null): void { - if($userInfo === null && $this->authInfo->loggedIn) - $userInfo = $this->authInfo->userInfo; - - $this->auditLog->createLog( - $userInfo, - $action, - $params, - $_SERVER['REMOTE_ADDR'] ?? '::1', - $_SERVER['COUNTRY_CODE'] ?? 'XX' - ); - } - private ?bool $hasManageAccess = null; public function hasManageAccess(): bool { $this->hasManageAccess ??= $this->authInfo->loggedIn @@ -190,6 +175,7 @@ class MisuzuContext { $routingCtx = $this->deps->construct(RoutingContext::class); $this->deps->register($this->urls = $routingCtx->urls); + $routingCtx->register($this->logsCtx); if(in_array('main', $roles)) $this->registerMainRoutes($routingCtx);