FINDINGS.md 6.6 KB

Findings: Аудит проекта PhotoPlaces

Дата аудита: 2026-06-13 Дата исправлений: 2026-06-14


Статус исправлений

✅ P0 — Исправлено

  1. WebSocket CheckOrigin — больше не return true. При пустом allowedOrigins в production соединения отклоняются.
  2. Sentinel error для "not your place" — заменён на ErrNotYourPlace с errors.Is-поддержкой.
  3. Dev-секреты в docker-compose.yml — вынесены в переменные ${VAR:-default}.
  4. env.prod — очищен от замусоренного placeholder Yandex-ключа.
  5. Docker secrets — config.go поддерживает _FILE suffix.
  6. JWT секреты без дефолтов в production — config.go требует JWT_SECRET, JWT_REFRESH_SECRET, ALLOWED_ORIGINS в production; дефолты ("dev-secret", "localhost:3000") запрещены, приложение паникует при старте.
  7. Token Reuse Detection — уже реализован: GetRevoked в репозитории, проверка в RefreshSession, отзыв всех токенов пользователя при обнаружении, обработка в хендлере.
  8. Скрытие внутренних ошибок в production — все хендлеры используют единый writeError с параметром err для логирования; в production 500 ошибки возвращают "internal server error" вместо деталей БД/логики.

✅ P1 — Исправлено

  1. Теги и фичи в листинге местPlaceFilter.IncludeTagsFeatures + batch-загрузка (GetTagsBatch/GetFeaturesBatch), запрос ?include=tags,features. N+1 проблема решена.

✅ P1 — Исправлено

  1. Rate limiter — Redis-based имплементация подключена в main.go, in-memory как fallback при недоступности Redis (реализован корректный fallback: при недоступности Redis автоматически используется in-memory limiter; в production failOpen=false — возвращается 503 только если оба лимитера недоступны).
  2. string(rune(line)) — код в log.go уже использует strconv.Itoa. Баг был исправлен до аудита.
  3. strPtr дублирование — удалён из handlers/helpers.go и services/auth.go. Создан единый pointer package.
  4. contains/searchString — код в repository/reviews.go использует errors.As напрямую. Проблема не актуальна.

✅ Тесты — Добавлены

  1. Backend unit-тесты:
    • services/auth_test.go — 6 тестов (регистрация, дубликат email, неверный пароль, бан, валидация токена, невалидный токен)
    • services/places_test.go — 3 теста (создание, не-владелец, неизвестный action модерации)
  2. Frontend тесты:
    • vitest + @testing-library/react
    • ErrorBoundary.test.tsx — 2 теста

✅ Frontend — Исправлено

  1. ErrorBoundary — создан компонент, подключён в layout.tsx
  2. catch {} — в admin/tags/page.tsx заменён на обработку с сообщением пользователю
  3. console.error — в MapView.tsx заменён на тихий catch (карта работает с текущими данными)

✅ Архитектура — Улучшено

  1. Dependency Inversion — в сервисы добавлены интерфейсы PlaceRepo, UserRepo, RefreshTokenRepo для тестируемости
  2. CSP — в Caddyfile добавлен Content-Security-Policy
  3. WebSocket — добавлен isProd флаг для безопасного fallback origins
  4. docker-compose.yml — все пароли через переменные окружения

⏳ P2 — Отложено

  1. MapLibre/OSM — только Yandex Maps. Задача на V2.
  2. Тесты frontend — база настроена (vitest), нужно расширять покрытие.
  3. CI/CD.github/dependabot.yml есть, но нет workflow. Нужен GitHub Actions.

Сводка изменений

Файл Изменение
backend/internal/services/places.go Sentinel errors + интерфейс PlaceRepo
backend/internal/services/auth.go Интерфейсы UserRepo/RefreshTokenRepo, убран strPtr
backend/internal/handlers/websocket.go isProd + CheckOrigin без fallback true
backend/internal/handlers/helpers.go Удалён strPtr
backend/internal/handlers/tags.go strPtr → pointer.Str
backend/internal/pointer/ Новый пакет (Str, Int, Float64)
backend/cmd/api/main.go isProd для WS Hub; rate limiter fallback (Redis → in-memory)
backend/internal/config/config.go JWT секреты обязательны в production, запрещены дефолты
backend/internal/handlers/errors.go Новый: единый writeError с логированием и скрытием деталей в prod
backend/internal/handlers/*.go Все хендлеры обновлены: writeError(msg, err) вместо err.Error()
backend/internal/models/place.go PlaceFilter.IncludeTagsFeatures
backend/internal/services/places.go List: batch-загрузка тегов/фич
backend/internal/repository/places.go GetTagsBatch, GetFeaturesBatch
backend/internal/handlers/places.go List: парсинг ?include=tags,features
docker-compose.yml Все пароли через ${VAR:-default}
deploy/env.prod Очищен Yandex-ключ
deploy/Caddyfile CSP + Permissions-Policy
frontend/src/components/ErrorBoundary.tsx Новый компонент
frontend/src/app/layout.tsx ErrorBoundary обёртка
frontend/src/app/admin/tags/page.tsx Обработка ошибок
frontend/src/components/MapView.tsx console.error → тихий catch
frontend/vitest.config.ts Новый файл
frontend/src/test/ setup.ts, ErrorBoundary.test.tsx
obsidian_data/Photoplaces_data/ 7 новых Zettelkasten-заметок