diff --git a/VKAPI/Handlers/Friends.php b/VKAPI/Handlers/Friends.php index 77de7d9d..4c109e13 100644 --- a/VKAPI/Handlers/Friends.php +++ b/VKAPI/Handlers/Friends.php @@ -98,6 +98,10 @@ final class Friends extends VKAPIRequestHandler switch ($user->getSubscriptionStatus($this->getUser())) { case 0: + if (\openvk\Web\Util\EventRateLimiter::i()->tryToLimit($this->getUser(), "friends.outgoing_sub")) { + $this->failTooOften(); + } + $user->toggleSubscription($this->getUser()); return 1; diff --git a/VKAPI/Handlers/Gifts.php b/VKAPI/Handlers/Gifts.php index 9ee5d222..460f11df 100644 --- a/VKAPI/Handlers/Gifts.php +++ b/VKAPI/Handlers/Gifts.php @@ -61,6 +61,10 @@ final class Gifts extends VKAPIRequestHandler $this->fail(-105, "Commerce is disabled on this instance"); } + if (\openvk\Web\Util\EventRateLimiter::i()->tryToLimit($this->getUser(), "gifts.send", false)) { + $this->failTooOften(); + } + $user = (new UsersRepo())->get((int) $user_ids); # FAKE прогноз погоды (в данном случае user_ids) if (!$user || $user->isDeleted()) { diff --git a/VKAPI/Handlers/Groups.php b/VKAPI/Handlers/Groups.php index 8933ca5a..707dc0f4 100644 --- a/VKAPI/Handlers/Groups.php +++ b/VKAPI/Handlers/Groups.php @@ -312,6 +312,10 @@ final class Groups extends VKAPIRequestHandler $isMember = !is_null($this->getUser()) ? (int) $club->getSubscriptionStatus($this->getUser()) : 0; if ($isMember == 0) { + if (\openvk\Web\Util\EventRateLimiter::i()->tryToLimit($this->getUser(), "groups.sub")) { + $this->failTooOften(); + } + $club->toggleSubscription($this->getUser()); } diff --git a/VKAPI/Handlers/Users.php b/VKAPI/Handlers/Users.php index bafce3d8..73ddcee4 100644 --- a/VKAPI/Handlers/Users.php +++ b/VKAPI/Handlers/Users.php @@ -317,6 +317,32 @@ final class Users extends VKAPIRequestHandler $response[$i]->custom_fields = $append_array; break; + case "bdate": + if (!$canView) { + $response[$i]->bdate = "01.01.1970"; + break; + } + $visibility = $usr->getBirthdayPrivacy(); + $response[$i]->bdate_visibility = $visibility; + + $birthday = $usr->getBirthday(); + if ($birthday) { + switch ($visibility) { + case 1: + $response[$i]->bdate = $birthday->format('%d.%m'); + break; + case 2: + $response[$i]->bdate = $birthday->format('%d.%m.%Y'); + break; + case 0: + default: + $response[$i]->bdate = null; + break; + } + } else { + $response[$i]->bdate = null; + } + break; } } diff --git a/VKAPI/Handlers/VKAPIRequestHandler.php b/VKAPI/Handlers/VKAPIRequestHandler.php index 4804a8dd..1f40fceb 100644 --- a/VKAPI/Handlers/VKAPIRequestHandler.php +++ b/VKAPI/Handlers/VKAPIRequestHandler.php @@ -25,6 +25,11 @@ abstract class VKAPIRequestHandler throw new APIErrorException($message, $code); } + protected function failTooOften(): never + { + $this->fail(9, "Rate limited"); + } + protected function getUser(): ?User { return $this->user; diff --git a/VKAPI/Handlers/Wall.php b/VKAPI/Handlers/Wall.php index 9113eb6e..c1a8619d 100644 --- a/VKAPI/Handlers/Wall.php +++ b/VKAPI/Handlers/Wall.php @@ -713,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"); @@ -723,7 +727,7 @@ final class Wall extends VKAPIRequestHandler } if ($owner_id > 0 && $owner_id !== $this->getUser()->getId()) { - (new WallPostNotification($wallOwner, $post, $this->user->identity))->emit(); + (new WallPostNotification($wallOwner, $post, $this->getUser()))->emit(); } return (object) ["post_id" => $post->getVirtualId()]; @@ -873,6 +877,8 @@ final class Wall extends VKAPIRequestHandler "id" => $comment->getId(), "from_id" => $oid, "date" => $comment->getPublicationTime()->timestamp(), + "can_edit" => $post->canBeEditedBy($this->getUser()), + "can_delete" => $post->canBeDeletedBy($this->getUser()), "text" => $comment->getText(false), "post_id" => $post->getVirtualId(), "owner_id" => method_exists($post, 'isPostedOnBehalfOfGroup') && $post->isPostedOnBehalfOfGroup() ? $post->getOwner()->getId() * -1 : $post->getOwner()->getId(), diff --git a/Web/Models/Entities/Post.php b/Web/Models/Entities/Post.php index 4079f566..bb833c04 100644 --- a/Web/Models/Entities/Post.php +++ b/Web/Models/Entities/Post.php @@ -176,11 +176,13 @@ class Post extends Postable $platform = $this->getRecord()->api_source_name; if ($forAPI) { switch ($platform) { + case 'openvk_native': case 'openvk_refresh_android': case 'openvk_legacy_android': return 'android'; break; + case 'openvk_native_ios': case 'openvk_ios': case 'openvk_legacy_ios': return 'iphone'; diff --git a/Web/Models/Entities/Traits/TSubscribable.php b/Web/Models/Entities/Traits/TSubscribable.php index 898f33a8..2e3f3bcd 100644 --- a/Web/Models/Entities/Traits/TSubscribable.php +++ b/Web/Models/Entities/Traits/TSubscribable.php @@ -34,9 +34,9 @@ trait TSubscribable "target" => $this->getId(), ]; $sub = $ctx->table("subscriptions")->where($data); - if (!($sub->fetch())) { $ctx->table("subscriptions")->insert($data); + return true; } diff --git a/Web/Models/Entities/User.php b/Web/Models/Entities/User.php index df4da4d0..e0fa0a76 100644 --- a/Web/Models/Entities/User.php +++ b/Web/Models/Entities/User.php @@ -971,11 +971,13 @@ class User extends RowModel $platform = $this->getRecord()->client_name; if ($forAPI) { switch ($platform) { + case 'openvk_native': case 'openvk_refresh_android': case 'openvk_legacy_android': return 'android'; break; + case 'openvk_native_ios': case 'openvk_ios': case 'openvk_legacy_ios': return 'iphone'; @@ -1738,4 +1740,52 @@ class User extends RowModel { return DatabaseConnection::i()->getContext()->table("blacklist_relations")->where("author", $this->getId())->count(); } + + public function getEventCounters(array $list): array + { + $count_of_keys = sizeof(array_keys($list)); + $ev_str = $this->getRecord()->events_counters; + $counters = []; + + if (!$ev_str) { + for ($i = 0; $i < sizeof(array_keys($list)); $i++) { + $counters[] = 0; + } + } else { + $counters = unpack("S" . $count_of_keys, base64_decode($ev_str, true)); + } + + return [ + 'counters' => array_combine(array_keys($list), $counters), + 'refresh_time' => $this->getRecord()->events_refresh_time, + ]; + } + + public function stateEvents(array $state_list): void + { + $pack_str = ""; + + foreach ($state_list as $item => $id) { + $pack_str .= "S"; + } + + $this->stateChanges("events_counters", base64_encode(pack($pack_str, ...array_values($state_list)))); + + if (!$this->getRecord()->events_refresh_time) { + $this->stateChanges("events_refresh_time", time()); + } + } + + public function resetEvents(array $list): void + { + $values = []; + + foreach ($list as $key => $val) { + $values[$key] = 0; + } + + $this->stateEvents($values); + $this->stateChanges("events_refresh_time", time()); + $this->save(); + } } diff --git a/Web/Presenters/AboutPresenter.php b/Web/Presenters/AboutPresenter.php index 9e8e975e..5d52db90 100644 --- a/Web/Presenters/AboutPresenter.php +++ b/Web/Presenters/AboutPresenter.php @@ -147,6 +147,29 @@ final class AboutPresenter extends OpenVKPresenter $this->redirect("https://github.com/openvk/openvk#readme"); } + public function renderAssetLinksJSON(): void + { + # Необходимо любому андроид приложению для автоматического разрешения принимать ссылки с этого сайта. + # Не шарю как писать норм на php поэтому тут чутка на вайбкодил - искренне ваш, ZAZiOs. + header("Content-Type: application/json"); + + $data = [ + [ + "relation" => ["delegate_permission/common.handle_all_urls"], + "target" => [ + "namespace" => "android_app", + "package_name" => "oss.OpenVK.Native", + "sha256_cert_fingerprints" => [ + "79:67:14:23:DC:6E:FA:49:64:1F:F1:81:0E:B0:A3:AE:6E:88:AB:0D:CF:BC:02:96:F3:6D:76:6B:82:94:D6:9C", + ], + ], + ], + ]; + + echo json_encode($data, JSON_UNESCAPED_SLASHES); + exit; + } + public function renderDev(): void { $this->redirect("https://docs.ovk.to/"); diff --git a/Web/Presenters/GiftsPresenter.php b/Web/Presenters/GiftsPresenter.php index 007be976..ec2993a4 100644 --- a/Web/Presenters/GiftsPresenter.php +++ b/Web/Presenters/GiftsPresenter.php @@ -106,6 +106,10 @@ final class GiftsPresenter extends OpenVKPresenter return; } + if (\openvk\Web\Util\EventRateLimiter::i()->tryToLimit($this->user->identity, "gifts.send")) { + $this->flashFail("err", tr("error"), tr("limit_exceed_exception")); + } + $comment = empty($c = $this->postParam("comment")) ? null : $c; $notification = new GiftNotification($user, $this->user->identity, $gift, $comment); $notification->emit(); diff --git a/Web/Presenters/GroupPresenter.php b/Web/Presenters/GroupPresenter.php index a38dacaa..99d5fa33 100644 --- a/Web/Presenters/GroupPresenter.php +++ b/Web/Presenters/GroupPresenter.php @@ -68,6 +68,10 @@ final class GroupPresenter extends OpenVKPresenter $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) { @@ -79,6 +83,7 @@ final class GroupPresenter extends OpenVKPresenter } $club->toggleSubscription($this->user->identity); + $this->redirect("/club" . $club->getId()); } else { $this->flashFail("err", tr("error"), tr("error_no_group_name")); @@ -103,6 +108,12 @@ final class GroupPresenter extends OpenVKPresenter $this->flashFail("err", tr("error"), tr("forbidden")); } + if (!$club->getSubscriptionStatus($this->user->identity)) { + if (\openvk\Web\Util\EventRateLimiter::i()->tryToLimit($this->user->identity, "groups.sub")) { + $this->flashFail("err", tr("error"), tr("limit_exceed_exception")); + } + } + $club->toggleSubscription($this->user->identity); $this->redirect($club->getURL()); diff --git a/Web/Presenters/ReportPresenter.php b/Web/Presenters/ReportPresenter.php index f58eaa5c..19254ab0 100644 --- a/Web/Presenters/ReportPresenter.php +++ b/Web/Presenters/ReportPresenter.php @@ -103,6 +103,10 @@ final class ReportPresenter extends OpenVKPresenter exit(json_encode([ "error" => "You can't report yourself" ])); } + if ($this->user->identity->isBannedInSupport()) { + exit(json_encode([ "reason" => $this->queryParam("reason") ])); + } + if (in_array($this->queryParam("type"), ["post", "photo", "video", "group", "comment", "note", "app", "user", "audio", "doc"])) { if (count(iterator_to_array($this->reports->getDuplicates($this->queryParam("type"), $id, null, $this->user->id))) <= 0) { $report = new Report(); diff --git a/Web/Presenters/UserPresenter.php b/Web/Presenters/UserPresenter.php index 7d152df4..869d601e 100644 --- a/Web/Presenters/UserPresenter.php +++ b/Web/Presenters/UserPresenter.php @@ -418,6 +418,12 @@ final class UserPresenter extends OpenVKPresenter if ($this->postParam("act") == "rej") { $user->changeFlags($this->user->identity, 0b10000000, true); } else { + if ($user->getSubscriptionStatus($this->user->identity) == \openvk\Web\Models\Entities\User::SUBSCRIPTION_ABSENT) { + if (\openvk\Web\Util\EventRateLimiter::i()->tryToLimit($this->user->identity, "friends.outgoing_sub")) { + $this->flashFail("err", tr("error"), tr("limit_exceed_exception")); + } + } + $user->toggleSubscription($this->user->identity); } 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/Presenters/templates/Admin/@layout.xml b/Web/Presenters/templates/Admin/@layout.xml index 055bd0a0..298dde14 100644 --- a/Web/Presenters/templates/Admin/@layout.xml +++ b/Web/Presenters/templates/Admin/@layout.xml @@ -2,15 +2,69 @@
+