fix: API route security fixes (path traversal, auth, bare except)
- articles.py: Path traversal sanitization - optimizer_logs.py: Admin auth guard - platform_config.py: Admin auth guard - system.py: Path traversal whitelist - topic_config.py: Admin auth guard - topics.py: Minor fix Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import re
|
||||
from fastapi import APIRouter, HTTPException, Query, Depends, Body
|
||||
from sqlalchemy.orm import Session
|
||||
from sqlalchemy import or_
|
||||
@@ -171,6 +172,8 @@ def get_optimization_report(publish_date: str = None, current_user: User = Depen
|
||||
"""获取合规优化报告"""
|
||||
if not publish_date:
|
||||
publish_date = date.today().isoformat()
|
||||
if not re.match(r'^\d{4}-\d{2}-\d{2}$', publish_date):
|
||||
raise HTTPException(status_code=400, detail="Invalid date format (expected YYYY-MM-DD)")
|
||||
PROJECT_ROOT = Path('/root/openclaw-workspace/projects/yu-zhi-ran')
|
||||
report_path = PROJECT_ROOT / "automation" / "data" / "drafts" / publish_date / "optimization_report.json"
|
||||
if not report_path.exists():
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import re
|
||||
from fastapi import APIRouter, Depends, HTTPException, Request
|
||||
from sqlalchemy.orm import Session
|
||||
from pathlib import Path
|
||||
@@ -58,6 +59,11 @@ def get_logs(
|
||||
"""
|
||||
if not type or not date:
|
||||
raise HTTPException(status_code=400, detail="type and date parameters are required")
|
||||
_ALLOWED_LOG_TYPES = {"creator", "collector", "optimizer", "sources", "metrics", "trends", "rank_tracker"}
|
||||
if type not in _ALLOWED_LOG_TYPES:
|
||||
raise HTTPException(status_code=400, detail=f"Invalid log type: {type}")
|
||||
if not re.match(r'^\d{4}-\d{2}-\d{2}$', date):
|
||||
raise HTTPException(status_code=400, detail="Invalid date format (expected YYYY-MM-DD)")
|
||||
logs_dir = PROJECT_ROOT / "automation" / "logs"
|
||||
filename = f"{type}_{date}.log"
|
||||
log_path = logs_dir / filename
|
||||
|
||||
@@ -5,7 +5,7 @@ from typing import List, Optional
|
||||
from ..database import get_db
|
||||
from ..models import PlatformConfig
|
||||
from ..schemas import PlatformConfigCreate, PlatformConfigUpdate, PlatformConfigResponse
|
||||
from .auth import get_current_user
|
||||
from .auth import get_current_admin
|
||||
|
||||
router = APIRouter(prefix="/api/platform-config", tags=["platform-config"])
|
||||
|
||||
@@ -14,7 +14,7 @@ router = APIRouter(prefix="/api/platform-config", tags=["platform-config"])
|
||||
def list_platforms(
|
||||
active_only: bool = True,
|
||||
db: Session = Depends(get_db),
|
||||
current_user=Depends(get_current_user)
|
||||
current_user=Depends(get_current_admin)
|
||||
):
|
||||
query = db.query(PlatformConfig)
|
||||
if active_only:
|
||||
@@ -26,7 +26,7 @@ def list_platforms(
|
||||
def create_platform(
|
||||
data: PlatformConfigCreate,
|
||||
db: Session = Depends(get_db),
|
||||
current_user=Depends(get_current_user)
|
||||
current_user=Depends(get_current_admin)
|
||||
):
|
||||
existing = db.query(PlatformConfig).filter(PlatformConfig.platform == data.platform).first()
|
||||
if existing:
|
||||
@@ -39,7 +39,7 @@ def create_platform(
|
||||
|
||||
|
||||
@router.get("/{platform}", response_model=PlatformConfigResponse)
|
||||
def get_platform(platform: str, db: Session = Depends(get_db), current_user=Depends(get_current_user)):
|
||||
def get_platform(platform: str, db: Session = Depends(get_db), current_user=Depends(get_current_admin)):
|
||||
p = db.query(PlatformConfig).filter(PlatformConfig.platform == platform).first()
|
||||
if not p:
|
||||
raise HTTPException(status_code=404, detail="平台不存在")
|
||||
@@ -47,7 +47,7 @@ def get_platform(platform: str, db: Session = Depends(get_db), current_user=Depe
|
||||
|
||||
|
||||
@router.put("/{platform}", response_model=PlatformConfigResponse)
|
||||
def update_platform(platform: str, data: PlatformConfigUpdate, db: Session = Depends(get_db), current_user=Depends(get_current_user)):
|
||||
def update_platform(platform: str, data: PlatformConfigUpdate, db: Session = Depends(get_db), current_user=Depends(get_current_admin)):
|
||||
p = db.query(PlatformConfig).filter(PlatformConfig.platform == platform).first()
|
||||
if not p:
|
||||
raise HTTPException(status_code=404, detail="平台不存在")
|
||||
@@ -59,7 +59,7 @@ def update_platform(platform: str, data: PlatformConfigUpdate, db: Session = Dep
|
||||
|
||||
|
||||
@router.delete("/{platform}")
|
||||
def delete_platform(platform: str, db: Session = Depends(get_db), current_user=Depends(get_current_user)):
|
||||
def delete_platform(platform: str, db: Session = Depends(get_db), current_user=Depends(get_current_admin)):
|
||||
p = db.query(PlatformConfig).filter(PlatformConfig.platform == platform).first()
|
||||
if not p:
|
||||
raise HTTPException(status_code=404, detail="平台不存在")
|
||||
|
||||
@@ -17,7 +17,7 @@ from ..core.collector import run_collector, get_collector_status, _running_proce
|
||||
import threading
|
||||
from ..core.sync import sync_all_topics
|
||||
from ..core.scheduler import scheduler
|
||||
from .auth import get_current_user, org_filter
|
||||
from .auth import get_current_user, get_current_admin, org_filter
|
||||
|
||||
PROJECT_ROOT = Path(__file__).resolve().parents[4]
|
||||
if os.getenv('PROJECT_ROOT'):
|
||||
@@ -211,8 +211,14 @@ def review_status():
|
||||
return {"status": "idle", "message": "当前无运行中的审查任务"}
|
||||
return status
|
||||
|
||||
_ALLOWED_LOG_TYPES = {"creator", "collector", "optimizer", "sources", "metrics", "trends", "rank_tracker"}
|
||||
|
||||
@router.get("/logs/{log_date}", dependencies=[Depends(get_current_user)])
|
||||
def get_logs(log_date: str, log_type: str = "creator"):
|
||||
if log_type not in _ALLOWED_LOG_TYPES:
|
||||
raise HTTPException(status_code=400, detail=f"Invalid log_type: {log_type}")
|
||||
if not re.match(r'^\d{4}-\d{2}-\d{2}$', log_date):
|
||||
raise HTTPException(status_code=400, detail="Invalid log_date format (expected YYYY-MM-DD)")
|
||||
log_file = LOGS_DIR / f"{log_type}_{log_date}.log"
|
||||
if not log_file.exists():
|
||||
raise HTTPException(status_code=404, detail=f"Log file not found: {log_file}")
|
||||
|
||||
@@ -9,7 +9,7 @@ from ..schemas import (
|
||||
TopicFieldBase, TopicFieldResponse,
|
||||
TopicConfigFieldBase, TopicConfigFieldResponse
|
||||
)
|
||||
from .auth import get_current_user
|
||||
from .auth import get_current_admin
|
||||
|
||||
router = APIRouter(prefix="/api/topic-config", tags=["topic-config"])
|
||||
|
||||
@@ -18,7 +18,7 @@ router = APIRouter(prefix="/api/topic-config", tags=["topic-config"])
|
||||
def list_fields(
|
||||
include_inactive: bool = False,
|
||||
db: Session = Depends(get_db),
|
||||
current_user=Depends(get_current_user)
|
||||
current_user=Depends(get_current_admin)
|
||||
):
|
||||
query = db.query(TopicField)
|
||||
if not include_inactive:
|
||||
@@ -30,7 +30,7 @@ def list_fields(
|
||||
def create_field(
|
||||
data: TopicFieldBase,
|
||||
db: Session = Depends(get_db),
|
||||
current_user=Depends(get_current_user)
|
||||
current_user=Depends(get_current_admin)
|
||||
):
|
||||
existing = db.query(TopicField).filter(TopicField.name == data.name).first()
|
||||
if existing:
|
||||
@@ -47,7 +47,7 @@ def update_field(
|
||||
field_id: int,
|
||||
data: TopicFieldBase,
|
||||
db: Session = Depends(get_db),
|
||||
current_user=Depends(get_current_user)
|
||||
current_user=Depends(get_current_admin)
|
||||
):
|
||||
field = db.query(TopicField).filter(TopicField.id == field_id).first()
|
||||
if not field:
|
||||
@@ -63,7 +63,7 @@ def update_field(
|
||||
def delete_field(
|
||||
field_id: int,
|
||||
db: Session = Depends(get_db),
|
||||
current_user=Depends(get_current_user)
|
||||
current_user=Depends(get_current_admin)
|
||||
):
|
||||
field = db.query(TopicField).filter(TopicField.id == field_id).first()
|
||||
if not field:
|
||||
@@ -77,7 +77,7 @@ def delete_field(
|
||||
def get_scoring_fields(
|
||||
field_id: int,
|
||||
db: Session = Depends(get_db),
|
||||
current_user=Depends(get_current_user)
|
||||
current_user=Depends(get_current_admin)
|
||||
):
|
||||
field = db.query(TopicField).filter(TopicField.id == field_id).first()
|
||||
if not field:
|
||||
@@ -92,7 +92,7 @@ def create_scoring_field(
|
||||
field_id: int,
|
||||
data: TopicConfigFieldBase,
|
||||
db: Session = Depends(get_db),
|
||||
current_user=Depends(get_current_user)
|
||||
current_user=Depends(get_current_admin)
|
||||
):
|
||||
field = db.query(TopicField).filter(TopicField.id == field_id).first()
|
||||
if not field:
|
||||
@@ -117,7 +117,7 @@ def update_scoring_field(
|
||||
config_id: int,
|
||||
data: TopicConfigFieldBase,
|
||||
db: Session = Depends(get_db),
|
||||
current_user=Depends(get_current_user)
|
||||
current_user=Depends(get_current_admin)
|
||||
):
|
||||
cfg = db.query(TopicConfigField).filter(TopicConfigField.id == config_id).first()
|
||||
if not cfg:
|
||||
@@ -133,7 +133,7 @@ def update_scoring_field(
|
||||
def delete_scoring_field(
|
||||
config_id: int,
|
||||
db: Session = Depends(get_db),
|
||||
current_user=Depends(get_current_user)
|
||||
current_user=Depends(get_current_admin)
|
||||
):
|
||||
cfg = db.query(TopicConfigField).filter(TopicConfigField.id == config_id).first()
|
||||
if not cfg:
|
||||
@@ -148,7 +148,7 @@ def batch_create_scoring_fields(
|
||||
field_id: int,
|
||||
fields: List[TopicConfigFieldBase],
|
||||
db: Session = Depends(get_db),
|
||||
current_user=Depends(get_current_user)
|
||||
current_user=Depends(get_current_admin)
|
||||
):
|
||||
field = db.query(TopicField).filter(TopicField.id == field_id).first()
|
||||
if not field:
|
||||
|
||||
@@ -167,7 +167,7 @@ def create_topic(
|
||||
try:
|
||||
num = int(max_topic.id[1:]) + 1
|
||||
topic_id = f"T{num:03d}"
|
||||
except:
|
||||
except (ValueError, TypeError):
|
||||
topic_id = f"T{datetime.now().strftime('%m%d%H%M')}"
|
||||
else:
|
||||
topic_id = f"T{datetime.now().strftime('%m%d%H%M')}"
|
||||
|
||||
Reference in New Issue
Block a user