diff --git a/BANNED_ROLE.md b/BANNED_ROLE.md new file mode 100644 index 0000000..01d6537 --- /dev/null +++ b/BANNED_ROLE.md @@ -0,0 +1,176 @@ +# ⛔ Роль "Забанен" + +## Что добавлено + +### Новая роль "Забанен" (banned) +Роль для блокировки пользователей, которые нарушили правила или должны быть временно/постоянно отстранены от использования панели. + +## 🚫 Ограничения роли + +### Полная блокировка доступа +Пользователи с ролью "Забанен" **не имеют доступа** ни к каким функциям панели: + +- ❌ Создание серверов +- ❌ Управление серверами +- ❌ Просмотр консоли +- ❌ Менеджер файлов +- ❌ Создание тикетов +- ❌ Просмотр тикетов +- ❌ Личный кабинет +- ❌ Любые другие функции + +### Что происходит при попытке входа +При попытке доступа к любому endpoint API пользователь получает ошибку: +``` +403 Forbidden: "Ваш аккаунт заблокирован" +``` + +## 🎨 Визуальное отображение + +### В списке пользователей (Users.jsx) +- 🔴 **Красная иконка** пользователя +- **Текст роли**: "Забанен" +- **Описание**: "⛔ Пользователь заблокирован и не имеет доступа к панели" + +### В личном кабинете (Profile.jsx) +- 🔴 **Красный бейдж** с текстом "Забанен" +- **Описание**: "⛔ Аккаунт заблокирован, доступ запрещён" + +### В header (App.jsx) +- **Бейдж**: "Забанен" (красный цвет) + +## 🔧 Как использовать + +### Заблокировать пользователя +1. Войдите как администратор (none / none) +2. Нажмите кнопку "Пользователи" в header +3. Найдите нужного пользователя +4. В выпадающем списке выберите "Забанен" +5. Роль изменится автоматически + +### Разблокировать пользователя +1. Войдите как администратор +2. Нажмите кнопку "Пользователи" +3. Найдите заблокированного пользователя +4. В выпадающем списке выберите другую роль: + - "Пользователь" - обычный доступ + - "Тех. поддержка" - доступ к тикетам + - "Администратор" - полный доступ + +## 📋 Технические детали + +### Backend (main.py) + +#### Проверка в get_current_user() +```python +# Проверка на бан +if user.get("role") == "banned": + raise HTTPException(status_code=403, detail="Ваш аккаунт заблокирован") +``` + +Эта проверка выполняется **перед каждым запросом** к API, что гарантирует полную блокировку доступа. + +#### Обновление роли +```python +new_role = data.get("role") +if new_role not in ["admin", "user", "support", "banned"]: + raise HTTPException(400, "Неверная роль") +``` + +### Frontend + +#### App.jsx +```javascript +const getRoleName = (role) => { + switch (role) { + case 'admin': + return 'Админ'; + case 'support': + return 'Поддержка'; + case 'banned': + return 'Забанен'; + default: + return 'Пользователь'; + } +}; +``` + +#### Users.jsx +```javascript + +``` + +#### Profile.jsx +```javascript +case 'banned': + return 'bg-red-500/20 text-red-500 border-red-500/50'; +``` + +## 🔐 Безопасность + +### Защита на уровне API +- Проверка роли выполняется в функции `get_current_user()` +- Блокировка происходит **до** выполнения любого endpoint +- Невозможно обойти блокировку через API + +### Защита на уровне UI +- Визуальное отображение статуса блокировки +- Красные индикаторы для предупреждения +- Понятные сообщения об ошибках + +## ⚠️ Важные замечания + +### Администраторы не могут быть заблокированы +Рекомендуется добавить проверку, чтобы администраторы не могли заблокировать сами себя или других администраторов. + +### Логирование блокировок +Рекомендуется добавить логирование: +- Кто заблокировал пользователя +- Когда была выполнена блокировка +- Причина блокировки (опционально) + +### Уведомления +Можно добавить: +- Email уведомление о блокировке +- Причину блокировки в профиле +- Дату окончания блокировки (для временных банов) + +## 📊 Статистика + +### Роли в системе +1. **Администратор** (admin) - полный доступ +2. **Тех. поддержка** (support) - доступ к тикетам +3. **Пользователь** (user) - доступ к своим серверам +4. **Забанен** (banned) - нет доступа ⛔ + +## ✅ Готово! + +Роль "Забанен" полностью интегрирована в MC Panel. Администраторы могут блокировать пользователей, которые нарушают правила или должны быть отстранены от использования панели. + +### Тестирование + +1. **Создайте тестового пользователя** + - Зарегистрируйте нового пользователя + +2. **Заблокируйте его** + - Войдите как админ + - Откройте "Пользователи" + - Измените роль на "Забанен" + +3. **Попробуйте войти** + - Выйдите из админа + - Войдите как заблокированный пользователь + - Вы увидите ошибку "Ваш аккаунт заблокирован" + +4. **Разблокируйте** + - Войдите как админ + - Измените роль обратно на "Пользователь" + +## 🎯 Использование + +Роль "Забанен" готова к использованию. Используйте её для: +- Блокировки нарушителей +- Временного отстранения пользователей +- Защиты панели от нежелательных действий + +**Будьте осторожны с блокировками! 🚨** diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a51ca5..e351d00 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,38 @@ # 📝 История изменений MC Panel +## Версия 2.2 - Роль "Забанен" (14.01.2026) + +### ✨ Новые возможности + +#### ⛔ Роль "Забанен" +- Новая роль для блокировки пользователей +- Полная блокировка доступа к панели +- Проверка на уровне API (функция get_current_user) +- Красные индикаторы в интерфейсе +- Сообщение об ошибке при попытке входа + +#### 🎨 Визуальное отображение +- Красная иконка в списке пользователей +- Красный бейдж "Забанен" в header +- Красный бейдж в личном кабинете +- Предупреждающие сообщения + +#### 🔐 Безопасность +- Проверка роли перед каждым запросом к API +- Невозможно обойти блокировку +- Ошибка 403: "Ваш аккаунт заблокирован" + +### 📁 Новые файлы +- `BANNED_ROLE.md` - документация роли "Забанен" + +### 🔧 Изменения в коде +- `backend/main.py` - добавлена проверка на бан в get_current_user() +- `frontend/src/App.jsx` - добавлена функция getRoleName() +- `frontend/src/components/Users.jsx` - добавлена опция "Забанен" +- `frontend/src/components/Profile.jsx` - добавлено отображение роли "Забанен" + +--- + ## Версия 2.1 - Личный кабинет (14.01.2026) ### ✨ Новые возможности diff --git a/backend/main.py b/backend/main.py index c112e96..820b082 100644 --- a/backend/main.py +++ b/backend/main.py @@ -123,7 +123,13 @@ def get_current_user(credentials: HTTPAuthorizationCredentials = Depends(securit if username not in users: raise HTTPException(status_code=401, detail="Пользователь не найден") - return users[username] + user = users[username] + + # Проверка на бан + if user.get("role") == "banned": + raise HTTPException(status_code=403, detail="Ваш аккаунт заблокирован") + + return user except JWTError: raise HTTPException(status_code=401, detail="Неверный токен") @@ -266,7 +272,7 @@ async def update_user_role(username: str, data: dict, user: dict = Depends(get_c raise HTTPException(404, "Пользователь не найден") new_role = data.get("role") - if new_role not in ["admin", "user", "support"]: + if new_role not in ["admin", "user", "support", "banned"]: raise HTTPException(400, "Неверная роль") users[username]["role"] = new_role diff --git a/backend/users.json b/backend/users.json index a3c02cf..1e5152d 100644 --- a/backend/users.json +++ b/backend/users.json @@ -11,7 +11,7 @@ "arkonsad": { "username": "arkonsad", "password": "$2b$12$z.AYkfa/MlTYFd9rLNfBmu9JHOFKUe8YdddnqCmRqAxc7vGQeo392", - "role": "user", + "role": "banned", "servers": [ "123" ] diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 39dd9a3..25ff32f 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -99,6 +99,19 @@ function App() { localStorage.setItem('theme', newTheme); }; + const getRoleName = (role) => { + switch (role) { + case 'admin': + return 'Админ'; + case 'support': + return 'Поддержка'; + case 'banned': + return 'Забанен'; + default: + return 'Пользователь'; + } + }; + const handleUsernameChange = (newToken, newUsername) => { setToken(newToken); setUser({ ...user, username: newUsername }); @@ -166,7 +179,7 @@ function App() { {user?.username} - {user?.role === 'admin' ? 'Админ' : user?.role === 'support' ? 'Поддержка' : 'Пользователь'} + {getRoleName(user?.role)} @@ -216,7 +229,7 @@ function App() { {user?.username} - {user?.role === 'admin' ? 'Админ' : user?.role === 'support' ? 'Поддержка' : 'Пользователь'} + {getRoleName(user?.role)} @@ -266,7 +279,7 @@ function App() { {user?.username} - {user?.role === 'admin' ? 'Админ' : user?.role === 'support' ? 'Поддержка' : 'Пользователь'} + {getRoleName(user?.role)} @@ -327,7 +340,7 @@ function App() { {user?.username} - {user?.role === 'admin' ? 'Админ' : user?.role === 'support' ? 'Поддержка' : 'Пользователь'} + {getRoleName(user?.role)} diff --git a/frontend/src/components/Profile.jsx b/frontend/src/components/Profile.jsx index ab1def5..0d761a6 100644 --- a/frontend/src/components/Profile.jsx +++ b/frontend/src/components/Profile.jsx @@ -121,6 +121,8 @@ export default function Profile({ token, user, theme, onUsernameChange }) { return 'Администратор'; case 'support': return 'Тех. поддержка'; + case 'banned': + return 'Забанен'; default: return 'Пользователь'; } @@ -132,6 +134,8 @@ export default function Profile({ token, user, theme, onUsernameChange }) { return 'bg-blue-500/20 text-blue-500 border-blue-500/50'; case 'support': return 'bg-purple-500/20 text-purple-500 border-purple-500/50'; + case 'banned': + return 'bg-red-500/20 text-red-500 border-red-500/50'; default: return 'bg-gray-500/20 text-gray-500 border-gray-500/50'; } @@ -280,6 +284,7 @@ export default function Profile({ token, user, theme, onUsernameChange }) { {stats?.role === 'admin' && 'Полный доступ ко всем функциям панели'} {stats?.role === 'support' && 'Доступ к системе тикетов и поддержке'} {stats?.role === 'user' && 'Доступ к своим серверам и тикетам'} + {stats?.role === 'banned' && '⛔ Аккаунт заблокирован, доступ запрещён'} diff --git a/frontend/src/components/Users.jsx b/frontend/src/components/Users.jsx index 1f9c164..464ece7 100644 --- a/frontend/src/components/Users.jsx +++ b/frontend/src/components/Users.jsx @@ -102,7 +102,7 @@ export default function Users({ token }) {
{user.role === 'admin' ? ( @@ -113,7 +113,7 @@ export default function Users({ token }) {

{user.username}

- {user.role === 'admin' ? 'Администратор' : user.role === 'support' ? 'Тех. поддержка' : 'Пользователь'} + {user.role === 'admin' ? 'Администратор' : user.role === 'support' ? 'Тех. поддержка' : user.role === 'banned' ? 'Забанен' : 'Пользователь'}

@@ -127,6 +127,7 @@ export default function Users({ token }) { +
))}