Steam Verification
1. Summary
Goal: Валидация Steam-аккаунтов пользователей для защиты от фрода и ботов. Система проверяет подлинность аккаунта через Steam API перед разрешением участия в розыгрышах и вывода предметов.
User Value: Возможность выводить выигранные скины в Steam и участвовать в розыгрышах. Путь: Trade URL → Верификация → Доступ к выводу/раффлам.
2. Business Logic
Verification Types
- Automatic
- Manual
Доступ: Автоматический при установке Trade URL
Проверки:
- Профиль публичный (visibility state = 3)
- Возраст аккаунта ≥ 30 дней
- Стоимость библиотеки ≥ 1000 RUB
- Библиотека игр видима
Результат: steamVerified = true, steamVerifiedAt = timestamp
Доступ: Через заявку в поддержку (тип: VERIFICATION_REQUEST)
Когда нужна:
- Новый аккаунт (< 30 дней)
- Низкая стоимость библиотеки
- Приватная библиотека с причиной
Результат: steamManuallyVerified = true после одобрения админом
См. также: Feedback для workflow обработки заявок
Verification Flow
Protection
| Действие | Rate Limit | Auth | Validation |
|---|---|---|---|
| Установить Trade URL | general (100/min) | Telegram | UpdateTradeUrlSchema |
| Удалить Trade URL | general (100/min) | Telegram | — |
| Получить статус | general (100/min) | Telegram | — |
См. Security Matrix для полного обзора защит.
Anti-Fraud Mechanisms
1. 7-Day Cooldown
Пользователь не может менять Steam-аккаунт чаще, чем раз в 7 дней.
Предотвращает быструю смену аккаунтов для обхода банов или эксплуатации системы наград.
2. BannedSteamId Auto-Ban
При попытке привязать забаненный Steam ID:
- Пользователь автоматически банится
- Причина: "Violation of service terms"
- Возвращается ошибка
VERIFICATION_FAILED(HTTP 403)
Знание Trade URL забаненного аккаунта = связь с нарушителем. Система трактует это как попытку обхода бана.
3. Active Withdrawal Check
Нельзя изменить Trade URL, если есть активный вывод предмета (статусы PENDING, PROCESSING, SENT).
4. Uniqueness Constraint
Один Steam ID может быть привязан только к одному аккаунту GOLOOT.
Edge Cases
UI поведение:
| Ситуация | UI поведение | Код ошибки |
|---|---|---|
| ❌ Неверный формат URL | Toast "Неверный формат Trade URL" | INVALID_TRADE_URL |
| 🔒 Профиль приватный | Toast "Сделайте профиль Steam публичным" | PROFILE_PRIVATE |
| 🎮 Игры скрыты | Toast "Откройте библиотеку игр" | GAMES_PRIVATE |
| 📅 Аккаунт новый | Toast "Аккаунт должен быть старше 30 дней" | ACCOUNT_TOO_NEW |
| 💰 Библиотека < 1000₽ | Toast "Стоимость библиотеки должна быть ≥ 1000₽" | LIBRARY_VALUE_TOO_LOW |
| 👤 ID занят другим | Toast "Этот Steam уже привязан к другому аккаунту" | STEAM_ID_TAKEN |
| ⏱️ Cooldown активен | Toast "Подождите X дней до смены аккаунта" | COOLDOWN_ACTIVE |
| 🚫 Забаненный Steam ID | BannedScreen (пользователь забанен) | VERIFICATION_FAILED |
| 🌐 Steam API недоступен | Toast "Попробуйте позже" | API_ERROR |
Backend Error Details
| Код | HTTP | Описание |
|---|---|---|
INVALID_TRADE_URL | 400 | Trade URL не распознан (не содержит partner параметр) |
PROFILE_PRIVATE | 400 | communityvisibilitystate !== 3 |
GAMES_PRIVATE | 400 | getOwnedGames() вернул пустой массив |
ACCOUNT_TOO_NEW | 400 | daysSince(timecreated) < 30 |
LIBRARY_VALUE_TOO_LOW | 400 | reachedThreshold === false |
STEAM_ID_TAKEN | 400 | Найден другой User с таким steamId |
COOLDOWN_ACTIVE | 400 | daysSince(steamIdChangedAt) < 7 |
VERIFICATION_FAILED | 403 | Steam ID в таблице BannedSteamId → auto-ban |
API_ERROR | 500 | Steam API вернул ошибку или недоступен |
3. ADR (Architectural Decisions)
Почему Trade URL, а не Steam OAuth?
Проблема: Нужен способ идентификации Steam-аккаунта и возможность отправлять трейды.
Решение: Пользователь вводит Trade URL из настроек Steam.
Альтернативы (отклонены):
- Steam OAuth — требует сложной интеграции, не даёт Trade URL
- Ручной ввод SteamID — пользователи путаются между форматами ID
Последствия: Простота для пользователя (copy-paste), но требует парсинга URL.
Почему 7-дневный cooldown?
Проблема: Пользователи могут быстро переключать аккаунты для обхода ограничений.
Решение: Cooldown 7 дней между сменами Steam-аккаунта.
Альтернативы (отклонены):
- Без cooldown — слишком просто обойти систему
- 30 дней — слишком строго для легитимных случаев
Последствия: Баланс между безопасностью и UX.
Почему auto-ban за BannedSteamId?
Автоматический бан — жёсткая мера, но необходима для борьбы с мультиаккаунтингом.
Проблема: Забаненные пользователи создают новые аккаунты и пытаются привязать тот же Steam.
Решение: Автоматический бан + запись в логи для расследования.
Альтернативы (отклонены):
- Только предупреждение — неэффективно против злоумышленников
- Ручная проверка — масштабируется плохо
Последствия: Эффективная защита, но риск false-positive (передача аккаунта/компьютера).
4. Architecture
Services Overview
Key Components
| Компонент | Путь | Описание |
|---|---|---|
| SteamVerificationService | backend/src/domains/steam-verification/services/steam-verification.service.ts | Оркестратор верификации |
| SteamApiClient | backend/src/domains/steam-verification/services/steam-api.client.ts | Клиент Steam Web API |
| Types | backend/src/domains/steam-verification/types/steam-api.types.ts | TypeScript типы |
| Routes | backend/src/domains/users/routes/profile.routes.ts:209-400 | API эндпоинты |
| Schemas | backend/src/domains/users/schemas/profile.schemas.ts:218-268 | Валидация |
5. Database Schema
User Steam Fields
| Поле | Тип | Описание |
|---|---|---|
steamId | String? (unique) | SteamID64, извлечён из Trade URL |
steamTradeUrl | String? | Полный Trade URL |
steamLinkedAt | DateTime? | Когда впервые привязан |
steamVerified | Boolean | Автоматическая верификация |
steamVerifiedAt | DateTime? | Когда верифицирован |
steamManuallyVerified | Boolean | Ручная верификация админом |
steamManuallyVerifiedAt | DateTime? | Когда одобрено |
steamAccountCreatedAt | DateTime? | Дата создания Steam-аккаунта |
steamLibraryValueUsd | Float? | Стоимость библиотеки |
steamGamesCount | Int? | Количество игр |
steamIdChangedAt | DateTime? | Последняя смена аккаунта (для cooldown) |
BannedSteamId Model
| Поле | Тип | Описание |
|---|---|---|
id | String (PK) | CUID |
steamId | String (unique) | Забаненный SteamID64 |
originalUserId | String | ID забаненного пользователя |
reason | String? | Причина бана (до 500 символов) |
bannedAt | DateTime | Когда забанен |
bannedBy | String? | ID админа |
Relationships
6. API Endpoints
| Метод | Эндпоинт | Описание | Docs |
|---|---|---|---|
| PUT | /api/users/steam/trade-url | Установить Trade URL и запустить верификацию | → |
| DELETE | /api/users/steam/trade-url | Удалить привязку Steam | → |
| GET | /api/users/verification-status | Получить статус верификации | → |
Response Examples
PUT /steam/trade-url (Success):
{
"success": true,
"data": {
"steamId": "76561198012345678",
"personaName": "PlayerName",
"profileUrl": "https://steamcommunity.com/id/playername",
"libraryValueUsd": 1500,
"gamesCount": 45,
"isVerified": true
}
}
GET /verification-status:
{
"success": true,
"data": {
"hasVerificationRequest": false,
"status": null,
"isVerified": true,
"canSubmitNew": false,
"lastRequestDate": null,
"adminNote": null
}
}
7. Related
- Profile — общие настройки профиля
- Steam Trade Bot — вывод предметов в Steam
- Feedback — ручная верификация через тикеты
- Raffle — требует верификацию для участия
- Withdraw Readiness — проверка готовности к выводу