diff --git a/.env.example b/.env.example index 70e5128..bb4bf98 100644 --- a/.env.example +++ b/.env.example @@ -57,6 +57,7 @@ ENABLE_ALL_BEATMAP_LEADERBOARD=false # 启用所有谱面的排行榜(没有 ENABLE_ALL_BEATMAP_PP=false # 允许任何谱面获得 PP SUSPICIOUS_SCORE_CHECK=true # 是否检查可疑的分数,默认开启 SEASONAL_BACKGROUNDS='[]' # 季节背景图 URL 列表 +BANNED_NAME='["mrekk", "vaxei", "btmc", "cookiezi", "peppy", "saragi", "chocomint"]' # 禁止使用的用户名列表 # 存储服务设置 # 支持的存储类型:local(本地存储)、r2(Cloudflare R2)、s3(AWS S3) diff --git a/README.en.md b/README.en.md index ed2cce2..5bceb03 100644 --- a/README.en.md +++ b/README.en.md @@ -115,6 +115,7 @@ The Fetcher is used to get data from the official osu! API using OAuth 2.0 authe | `ENABLE_ALL_BEATMAP_PP` | Allow any beatmap to grant PP | `false` | | `SUSPICIOUS_SCORE_CHECK` | Enable suspicious score check (star>25 & acc<80 or pp>2300) | `true` | | `SEASONAL_BACKGROUNDS` | List of seasonal background URLs | `[]` | +| `BANNED_NAME` | List of banned usernames | `["mrekk", "vaxei", "btmc", "cookiezi", "peppy", "saragi", "chocomint"]` | ### Storage Service Settings diff --git a/README.md b/README.md index 4a6acd4..a74916e 100644 --- a/README.md +++ b/README.md @@ -119,6 +119,7 @@ Fetcher 用于从 osu! 官方 API 获取数据,使用 osu! 官方 API 的 OAut | `ENABLE_ALL_BEATMAP_PP` | 允许任何谱面获得 PP | `false` | | `SUSPICIOUS_SCORE_CHECK` | 启用可疑分数检查(star>25&acc<80 或 pp>2300) | `true` | | `SEASONAL_BACKGROUNDS` | 季节背景图 URL 列表 | `[]` | +| `BANNED_NAME` | 禁止使用的用户名列表 | `["mrekk", "vaxei", "btmc", "cookiezi", "peppy", "saragi", "chocomint"]` | ### 存储服务设置 diff --git a/app/auth.py b/app/auth.py index c1a0000..6293c07 100644 --- a/app/auth.py +++ b/app/auth.py @@ -2,6 +2,7 @@ from __future__ import annotations from datetime import datetime, timedelta import hashlib +import re import secrets import string @@ -26,6 +27,36 @@ pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") bcrypt_cache = {} +def validate_username(username: str) -> list[str]: + """验证用户名""" + errors = [] + + if not username: + errors.append("Username is required") + return errors + + if len(username) < 3: + errors.append("Username must be at least 3 characters long") + + if len(username) > 15: + errors.append("Username must be at most 15 characters long") + + # 检查用户名格式(只允许字母、数字、下划线、连字符) + if not re.match(r"^[a-zA-Z0-9_-]+$", username): + errors.append( + "Username can only contain letters, numbers, underscores, and hyphens" + ) + + # 检查是否以数字开头 + if username[0].isdigit(): + errors.append("Username cannot start with a number") + + if username.lower() in settings.banned_name: + errors.append("This username is not allowed") + + return errors + + def verify_password_legacy(plain_password: str, bcrypt_hash: str) -> bool: """ 验证密码 - 使用 osu! 的验证方式 diff --git a/app/config.py b/app/config.py index 8350eeb..e794e09 100644 --- a/app/config.py +++ b/app/config.py @@ -109,6 +109,15 @@ class Settings(BaseSettings): enable_all_beatmap_pp: bool = False suspicious_score_check: bool = True seasonal_backgrounds: list[str] = [] + banned_name: list[str] = [ + "mrekk", + "vaxei", + "btmc", + "cookiezi", + "peppy", + "saragi", + "chocomint", + ] # 存储设置 storage_service: StorageServiceType = StorageServiceType.LOCAL diff --git a/app/router/auth.py b/app/router/auth.py index d563ed3..bc7b02e 100644 --- a/app/router/auth.py +++ b/app/router/auth.py @@ -12,6 +12,7 @@ from app.auth import ( get_token_by_refresh_token, get_user_by_authorization_code, store_token, + validate_username, ) from app.config import settings from app.const import BANCHOBOT_ID @@ -46,33 +47,6 @@ def create_oauth_error_response( return JSONResponse(status_code=status_code, content=error_data.model_dump()) -def validate_username(username: str) -> list[str]: - """验证用户名""" - errors = [] - - if not username: - errors.append("Username is required") - return errors - - if len(username) < 3: - errors.append("Username must be at least 3 characters long") - - if len(username) > 15: - errors.append("Username must be at most 15 characters long") - - # 检查用户名格式(只允许字母、数字、下划线、连字符) - if not re.match(r"^[a-zA-Z0-9_-]+$", username): - errors.append( - "Username can only contain letters, numbers, underscores, and hyphens" - ) - - # 检查是否以数字开头 - if username[0].isdigit(): - errors.append("Username cannot start with a number") - - return errors - - def validate_email(email: str) -> list[str]: """验证邮箱""" errors = [] diff --git a/app/router/private/username.py b/app/router/private/username.py index 9e0aa13..5319d2c 100644 --- a/app/router/private/username.py +++ b/app/router/private/username.py @@ -2,6 +2,7 @@ from __future__ import annotations from datetime import UTC, datetime +from app.auth import validate_username from app.config import settings from app.database.events import Event, EventType from app.database.lazer_user import User @@ -41,6 +42,9 @@ async def user_rename( ).first() if samename_user: raise HTTPException(409, "Username Exisits") + errors = validate_username(new_name) + if errors: + raise HTTPException(403, "\n".join(errors)) previous_username = [] previous_username.extend(current_user.previous_usernames) previous_username.append(current_user.username)