Files
g0v0-server/app/models/userpage.py
MingxuanGame e0c3e06ffe fix(bbcode): fix ReDos vulnerabilities in BBCodeService (#96)
* fix(bbcode): fix ReDos of imagemap parsing

* fix(bbcode): use `regex` and add timeout to avoid too long time to parse

* feat(bbcode): use `make_tag` to generate HTML tags

* docs(bbcode): add docstrings for BBCodeService

* fix(user): validate BBCode content before processing userpage update

* fix(bbcode): catch timeout errors in BBCode parsing with MaliciousBBCodeError

* fix(bbcode): resolve reviews

* fix(bbcode): use `make_tag` in `_parse_size`

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* fix(bbcode): fix using `make_tag` in `_parse_size`

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-12 19:50:29 +08:00

110 lines
3.1 KiB
Python
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.
"""
用户页面编辑相关的API模型
"""
from pydantic import BaseModel, Field, field_validator
class UpdateUserpageRequest(BaseModel):
"""更新用户页面请求模型匹配官方osu-web格式"""
body: str = Field(
description="用户页面的BBCode原始内容",
max_length=60000,
examples=["[b]Hello![/b] This is my profile page.\n[color=blue]Blue text[/color]"],
)
@field_validator("body")
@classmethod
def validate_body_content(cls, v: str) -> str:
"""验证原始内容"""
if not v.strip():
return ""
# 基本长度验证
if len(v) > 60000:
msg = "Content too long. Maximum 60000 characters allowed."
raise ValueError(msg)
return v
class UpdateUserpageResponse(BaseModel):
"""更新用户页面响应模型匹配官方osu-web格式"""
html: str = Field(description="处理后的HTML内容")
class UserpageResponse(BaseModel):
"""用户页面响应模型包含html和raw匹配官方格式"""
html: str = Field(description="处理后的HTML内容")
raw: str = Field(description="原始BBCode内容")
class ValidateBBCodeRequest(BaseModel):
"""验证BBCode请求模型"""
content: str = Field(description="要验证的BBCode内容", max_length=60000)
class ValidateBBCodeResponse(BaseModel):
"""验证BBCode响应模型"""
valid: bool = Field(description="BBCode是否有效")
errors: list[str] = Field(default_factory=list, description="错误列表")
preview: dict[str, str] = Field(description="预览内容")
class UserpageError(Exception):
"""用户页面处理错误基类"""
def __init__(self, message: str, code: str = "userpage_error"):
self.message = message
self.code = code
super().__init__(message)
class ContentTooLongError(UserpageError):
"""内容过长错误"""
def __init__(self, current_length: int, max_length: int):
message = f"Content too long. Maximum {max_length} characters allowed, got {current_length}."
super().__init__(message, "content_too_long")
self.current_length = current_length
self.max_length = max_length
class ContentEmptyError(UserpageError):
"""内容为空错误"""
def __init__(self):
super().__init__("Content cannot be empty.", "content_empty")
class BBCodeValidationError(UserpageError):
"""BBCode验证错误"""
def __init__(self, errors: list[str]):
message = f"BBCode validation failed: {'; '.join(errors)}"
super().__init__(message, "bbcode_validation_error")
self.errors = errors
class ForbiddenTagError(UserpageError):
"""禁止标签错误"""
def __init__(self, tag: str):
message = f"Forbidden tag '{tag}' is not allowed."
super().__init__(message, "forbidden_tag")
self.tag = tag
class MaliciousBBCodeError(UserpageError):
"""恶意BBCode错误"""
def __init__(self, detail: str):
message = f"Malicious BBCode detected: {detail}"
super().__init__(message, "malicious_bbcode")
self.detail = detail