From c3b1e46909fc07c8c0152072a14b9a070c5bc8d9 Mon Sep 17 00:00:00 2001 From: mrilyew <99399973+mrilyew@users.noreply.github.com> Date: Thu, 26 Jun 2025 13:14:52 +0300 Subject: [PATCH] draft no.0,33 --- VKAPI/Handlers/Wall.php | 10 ++-- Web/Models/Entities/User.php | 39 ++++++++++----- Web/Presenters/GiftsPresenter.php | 2 +- Web/Presenters/GroupPresenter.php | 8 +-- Web/Presenters/WallPresenter.php | 4 ++ Web/Util/EventRateLimiter.php | 81 +++++++++++-------------------- 6 files changed, 69 insertions(+), 75 deletions(-) diff --git a/VKAPI/Handlers/Wall.php b/VKAPI/Handlers/Wall.php index 5309f025..f1fdf978 100644 --- a/VKAPI/Handlers/Wall.php +++ b/VKAPI/Handlers/Wall.php @@ -620,10 +620,6 @@ final class Wall extends VKAPIRequestHandler return (object) ["post_id" => $post->getVirtualId()]; } - if (\openvk\Web\Util\EventRateLimiter::i()->tryToLimit($this->getUser(), "wall.post", false)) { - $this->failTooOften(); - } - $anon = OPENVK_ROOT_CONF["openvk"]["preferences"]["wall"]["anonymousPosting"]["enable"]; if ($wallOwner instanceof Club && $from_group == 1 && $signed != 1 && $anon) { $manager = $wallOwner->getManager($this->getUser()); @@ -717,6 +713,10 @@ final class Wall extends VKAPIRequestHandler $post->setSuggested(1); } + if (\openvk\Web\Util\EventRateLimiter::i()->tryToLimit($this->getUser(), "wall.post")) { + $this->failTooOften(); + } + $post->save(); } catch (\LogicException $ex) { $this->fail(100, "One of the parameters specified was missing or invalid"); @@ -730,8 +730,6 @@ final class Wall extends VKAPIRequestHandler (new WallPostNotification($wallOwner, $post, $this->getUser()))->emit(); } - \openvk\Web\Util\EventRateLimiter::i()->writeEvent("wall.post", $this->getUser(), $wallOwner); - return (object) ["post_id" => $post->getVirtualId()]; } diff --git a/Web/Models/Entities/User.php b/Web/Models/Entities/User.php index 80a787fa..3fb28776 100644 --- a/Web/Models/Entities/User.php +++ b/Web/Models/Entities/User.php @@ -1740,41 +1740,56 @@ class User extends RowModel return DatabaseConnection::i()->getContext()->table("blacklist_relations")->where("author", $this->getId())->count(); } - public function recieveEventsData(array $list): array + public function getEventCounters(array $list): array { $ev_str = $this->getRecord()->events_counters; - $values = []; + $counters = []; + $compared_counters = []; if (!$ev_str) { + bdump(sizeof(array_keys($list))); for ($i = 0; $i < sizeof(array_keys($list)); $i++) { - $values[] = 0; + $counters[] = 0; } } else { - $keys = array_keys($list); - $values = unpack("S*", base64_decode($ev_str)); + $counters = unpack("S*", base64_decode($ev_str)); } + $i = 1; + + foreach ($list as $name => $value) { + $compared_counters[$name] = $counters[$i] ?? 0; + $i += 1; + } + + bdump($counters); + bdump($compared_counters); return [ - 'counters' => $values, + 'counters' => $compared_counters, 'refresh_time' => $this->getRecord()->events_refresh_time, ]; } - public function stateEvents(array $list): void + public function stateEvents(array $state_list): void { - $this->stateChanges("events_counters", base64_encode(pack("S*", array_values($list)))); + bdump($state_list); + $this->stateChanges("events_counters", base64_encode(pack("S*", ...array_values($state_list)))); + + if (!$this->getRecord()->events_refresh_time) { + $this->stateChanges("events_refresh_time", time()); + } } - public function resetEvents(array $list, int $restriction_length) + public function resetEvents(array $list) { $values = []; - for ($i = 0; $i < sizeof(array_keys($list)); $i++) { - $values[] = 0; + foreach ($list as $key => $val) { + $values[$key] = 0; } $this->stateEvents($values); - $this->stateChanges("events_refresh_time", $restriction_length + time()); + $this->stateChanges("events_refresh_time", time()); $this->save(); } } diff --git a/Web/Presenters/GiftsPresenter.php b/Web/Presenters/GiftsPresenter.php index f945c342..ec2993a4 100644 --- a/Web/Presenters/GiftsPresenter.php +++ b/Web/Presenters/GiftsPresenter.php @@ -106,7 +106,7 @@ final class GiftsPresenter extends OpenVKPresenter return; } - if (\openvk\Web\Util\EventRateLimiter::i()->tryToLimit($this->user->identity, "gifts.send", false)) { + if (\openvk\Web\Util\EventRateLimiter::i()->tryToLimit($this->user->identity, "gifts.send")) { $this->flashFail("err", tr("error"), tr("limit_exceed_exception")); } diff --git a/Web/Presenters/GroupPresenter.php b/Web/Presenters/GroupPresenter.php index 96f69083..2151b503 100644 --- a/Web/Presenters/GroupPresenter.php +++ b/Web/Presenters/GroupPresenter.php @@ -63,15 +63,15 @@ final class GroupPresenter extends OpenVKPresenter if ($_SERVER["REQUEST_METHOD"] === "POST") { if (!empty($this->postParam("name")) && mb_strlen(trim($this->postParam("name"))) > 0) { - if (\openvk\Web\Util\EventRateLimiter::i()->tryToLimit($this->user->identity, "groups.create")) { - $this->flashFail("err", tr("error"), tr("limit_exceed_exception")); - } - $club = new Club(); $club->setName($this->postParam("name")); $club->setAbout(empty($this->postParam("about")) ? null : $this->postParam("about")); $club->setOwner($this->user->id); + if (\openvk\Web\Util\EventRateLimiter::i()->tryToLimit($this->user->identity, "groups.create")) { + $this->flashFail("err", tr("error"), tr("limit_exceed_exception")); + } + try { $club->save(); } catch (\PDOException $ex) { diff --git a/Web/Presenters/WallPresenter.php b/Web/Presenters/WallPresenter.php index dbdfdde0..53e662f6 100644 --- a/Web/Presenters/WallPresenter.php +++ b/Web/Presenters/WallPresenter.php @@ -356,6 +356,10 @@ final class WallPresenter extends OpenVKPresenter $this->flashFail("err", tr("failed_to_publish_post"), tr("post_is_empty_or_too_big")); } + if (\openvk\Web\Util\EventRateLimiter::i()->tryToLimit($this->user->identity, "wall.post")) { + $this->flashFail("err", tr("error"), tr("limit_exceed_exception")); + } + $should_be_suggested = $wall < 0 && !$wallOwner->canBeModifiedBy($this->user->identity) && $wallOwner->getWallType() == 2; try { $post = new Post(); diff --git a/Web/Util/EventRateLimiter.php b/Web/Util/EventRateLimiter.php index 7d3b0862..b381134b 100644 --- a/Web/Util/EventRateLimiter.php +++ b/Web/Util/EventRateLimiter.php @@ -13,19 +13,18 @@ class EventRateLimiter use TSimpleSingleton; private $config; - private $availableFields; public function __construct() { $this->config = OPENVK_ROOT_CONF["openvk"]["preferences"]["security"]["rateLimits"]["eventsLimit"]; - - $this->availableFields = array_keys($this->config['list']); } /* - Checks count of actions for last hours + Checks count of actions for last x seconds. - Uses config path OPENVK_ROOT_CONF["openvk"]["preferences"]["security"]["rateLimits"]["eventsLimit"] + Uses OPENVK_ROOT_CONF["openvk"]["preferences"]["security"]["rateLimits"]["eventsLimit"] + + This check should be peformed only after checking other conditions cuz by default it increments counter Returns: @@ -33,8 +32,9 @@ class EventRateLimiter false — the action can be performed */ - public function tryToLimit(?User $user, string $event_type, bool $distinct = true): bool + public function tryToLimit(?User $user, string $event_type, bool $is_update = true): bool { + bdump("TRY TO LIMIT IS CALLLLED"); $isEnabled = $this->config['enable']; $isIgnoreForAdmins = $this->config['ignoreForAdmins']; $restrictionTime = $this->config['restrictionTime']; @@ -49,74 +49,51 @@ class EventRateLimiter } $limitForThatEvent = $eventsList[$event_type]; - $stat = $this->getEvent($event_type, $user); - bdump($stat); + $eventsStats = $user->getEventCounters($eventsList); - $is_restrict_over = $stat["refresh_time"] < time() - $restrictionTime; + $counters = $eventsStats["counters"]; + $refresh_time = $eventsStats["refresh_time"]; + $is_restrict_over = $refresh_time < (time() - $restrictionTime); + bdump($refresh_time); + bdump("time: " . time()); + $event_counter = $counters[$event_type]; - if ($is_restrict_over) { - $user->resetEvents($eventsList, $restrictionTime); + if ($refresh_time && $is_restrict_over) { + bdump("RESETTING EVENT COUTNERS"); + $user->resetEvents($eventsList); return false; } - $is = $stat["compared"] > $limitForThatEvent; + $is_limit_exceed = $event_counter > $limitForThatEvent; - if ($is === false) { - $this->incrementEvent($event_type, $user); + bdump($is_limit_exceed); + if (!$is_limit_exceed && $is_update) { + $this->incrementEvent($counters, $event_type, $user); } - return $is; - } - - public function getEvent(string $event_type, User $by_user): array - { - $ev_data = $by_user->recieveEventsData($this->config['list']); - $values = $ev_data['counters']; - $i = 0; - - $compared = []; - bdump($values); - - foreach ($this->config['list'] as $name => $value) { - bdump($value); - $compared[$name] = $values[$i]; - $i += 1; - } - - return [ - "compared" => $compared, - "refresh_time" => $ev_data["refresh_time"] - ]; + return $is_limit_exceed; } /* Updates counter for user */ - public function incrementEvent(string $event_type, User $initiator): bool + public function incrementEvent(array $old_values, string $event_type, User $initiator): bool { + bdump("INCREMENT IS CALLED"); $isEnabled = $this->config['enable']; - $eventsList = OPENVK_ROOT_CONF["openvk"]["preferences"]["security"]["rateLimits"]["eventsLimit"]; + $eventsList = $this->config['list']; if (!$isEnabled) { return false; } + bdump($old_values); - $ev_data = $initiator->recieveEventsData($eventsList); - $values = $ev_data['counters']; - $i = 0; + $old_values[$event_type] += 1; - $compared = []; - - foreach ($eventsList as $name => $value) { - $compared[$name] = $values[$i]; - $i += 1; - } - - $compared[$event_type] += 1; - - bdump($compared); - $initiator->stateEvents($compared); + bdump($old_values); + $initiator->stateEvents($old_values); + $initiator->save(); return true; }