randomayzer/agents/antigravity/done/TASK-2026-08-21-13-preview-anonymous-policy.md

57 lines
4.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Task 13: Политика анонимного доступа к POST /api/posts/preview Report
**Date:** 2026-08-21
**Base Commit SHA:** `76ab7d0e77d06cbc31b66fc5c0cdd80282d7f496`
**Status:** COMPLETED / PASS
**Assigned Agent:** Antigravity (Implementation Orchestrator)
---
## 1. Исправление предыдущего утверждения (Correction of Finding)
В отчёте по Заданию 05 (`agents/antigravity/done/TASK-2026-08-21-05-post-preview-auth.md:37`) содержалось ошибочное утверждение:
> *"Quota Protection: Невозможно истощить квоту приложения анонимными запросами благодаря строгому ограничению IP."*
**Фактический анализ:**
1. При `TRUST_PROXY=true` злоумышленник с пулом IP-адресов мог линейно расходовать квоту `VK_SERVICE_TOKEN`, обходя per-IP лимитер.
2. При дефолтной конфигурации (`TRUST_PROXY` не задан, пустой `req.ip`) все анонимные клиенты делили один ключ `direct-client`. Превышение 15 запросов одним пользователем блокировало превью всем остальным анонимам, создавая DoS.
3. Весь сценарий визарда создания розыгрыша в интерфейсе (`handleFetchPost` -> `POST /api/giveaways`) требует авторизации через VK ID (`requireAuthenticatedUser`), поэтому анонимный доступ к превью не обслуживал ни один завершаемый пользовательский сценарий.
---
## 2. Принятое архитектурное решение: Вариант A (Обязательная аутентификация)
1. **Защита маршрута `POST /api/posts/preview` (`src/app/api/posts/preview/route.ts`):**
- На маршрут установлен вызов `const sessionUser = await requireAuthenticatedUser(req)`.
- Анонимные запросы без сессионной куки немедленно отклоняются с кодом `401 Unauthorized`.
- Запросы без авторизации **никогда не обращаются к VK API / провайдеру** (0 вызовов VK API, что математически и аппаратно доказано mock-счетчиками в тестах).
- Лимитирование переведено на `user-scoped` ключ организатора: `generalApiRateLimiter.assertAllowed('post-preview:user:' + sessionUser.id)` (120 запросов / мин).
2. **Интерфейс пользователя (`src/app/giveaways/new/page.tsx`):**
- Клиентский визард корректно обрабатывает 401 на этапе предпросмотра поста и выводит понятное сообщение: «Для создания розыгрыша и предпросмотра публикации необходимо войти через VK ID.» со ссылкой на вход, сохраняющей целевой URL.
---
## 3. Modified & Created Files
| File | Status | Description |
|------|--------|-------------|
| `src/app/api/posts/preview/route.ts` | MODIFIED | Установлен `requireAuthenticatedUser(req)` и user-scoped rate limiter. |
| `tests/preview-quota-policy.test.ts` | NEW | 4 теста: отсечение анонимов с 401 и 0 вызовов VK API, успешный preview для организатора, user-scoped лимит, CSRF-защита. |
| `tests/post-preview-guard.test.ts` | MODIFIED | Тест 3 обновлен под обязательную аутентификацию (401). |
| `tests/rate-limit-identity.test.ts` | MODIFIED | Тестирование `TRUST_PROXY=true` переведено на публичный эндпоинт `GET /api/giveaways/[id]/public`. |
| `tests/security.test.ts` | MODIFIED | В тест утечки токенов добавлена сессия организатора. |
| `tests/effective-capabilities-truthfulness.test.ts` | MODIFIED | Тест 4 обновлен для авторизованного пользователя без кастомных токенов. |
---
## 4. Verification Evidence
```text
npx prisma generate -> EXIT 0 (Prisma Client v5.22.0)
npx tsc --noEmit -> EXIT 0 (0 ошибок типизации во всех 59 тест-файлах и исходном коде)
npm test -> EXIT 0 (59 тест-сьютов, 342 теста пройдены успешно)
npm run lint -> EXIT 0 (0 ошибок, 6 warnings на no-img-element)
npm run build -> EXIT 0 (Все 17 маршрутов скомпилированы успешно в Next.js 16.3.2)
npm audit --omit=dev -> EXIT 0 (0 vulnerabilities)
```