233e23016c
- 文章 HTML 存储从文件系统迁移至 articles 表,删除 releases 目录 - 合规审查从 DB 读取 HTML,审查结果写回 DB,通过后自动推进至待发布 - 新增 todayCount 筛选按钮,与系统概览统计数据一致 - 全屏预览修复:提升 z-index 超过侧边栏,添加退出全屏/关闭按钮 - 统一 '优化' → '审查' 命名,消除前后端术语不一致 - 调度器创作完成后自动触发审查(生成 → 审查 → 待发布) - 清理旧备份/调试文件、过期大纲和研究笔记
111 lines
4.5 KiB
Python
111 lines
4.5 KiB
Python
#!/usr/bin/env python3
|
|
"""安全与错误处理测试"""
|
|
|
|
import sys
|
|
import os
|
|
import json
|
|
|
|
BASE_URL = "http://localhost:8001"
|
|
|
|
try:
|
|
import requests
|
|
except ImportError:
|
|
os.system("pip install requests -q")
|
|
import requests
|
|
|
|
def get_token():
|
|
r = requests.post(f"{BASE_URL}/api/auth/login", json={"username": "admin", "password": "admin123"})
|
|
return r.json()["token"] if r.status_code == 200 else None
|
|
|
|
def h(token):
|
|
return {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
|
|
|
|
def check(name, condition, details=""):
|
|
icon = "✅" if condition else "❌"
|
|
print(f" {icon} {name}{' (' + details + ')' if details else ''}")
|
|
return condition
|
|
|
|
def section(name):
|
|
print(f"\n{'='*50}")
|
|
print(f" {name}")
|
|
print(f"{'='*50}")
|
|
|
|
def main():
|
|
print("=" * 60)
|
|
print("宇之然平台 - 安全与错误处理测试")
|
|
print("=" * 60)
|
|
|
|
results = []
|
|
|
|
section("🔐 认证安全")
|
|
r = requests.get(f"{BASE_URL}/api/topics")
|
|
results.append(check("无 token 请求被拒绝", r.status_code == 401 or r.status_code == 403, f"HTTP {r.status_code}"))
|
|
|
|
r = requests.get(f"{BASE_URL}/api/topics", headers={"Authorization": "Bearer invalid_token"})
|
|
results.append(check("无效 token 被拒绝", r.status_code == 401 or r.status_code == 403, f"HTTP {r.status_code}"))
|
|
|
|
r = requests.get(f"{BASE_URL}/api/topics", headers={"Authorization": ""})
|
|
results.append(check("空 token 被拒绝", r.status_code == 401 or r.status_code == 403, f"HTTP {r.status_code}"))
|
|
|
|
r = requests.post(f"{BASE_URL}/api/auth/login", json={"username": "admin", "password": "wrong"})
|
|
results.append(check("错误密码登录失败", r.status_code == 401, f"HTTP {r.status_code}"))
|
|
|
|
r = requests.post(f"{BASE_URL}/api/auth/login", json={"username": "nonexistent", "password": "test"})
|
|
results.append(check("不存在的用户登录失败", r.status_code == 401, f"HTTP {r.status_code}"))
|
|
|
|
section("🛡️ CORS 安全")
|
|
r = requests.get(f"{BASE_URL}/api/system/status", headers=h(get_token()))
|
|
cors_origin = r.headers.get("access-control-allow-origin", "")
|
|
results.append(check("CORS 不返回通配符 *", cors_origin != "*", f"Origin: {cors_origin or '(none)'}"))
|
|
|
|
section("⚠️ 错误处理")
|
|
r = requests.get(f"{BASE_URL}/api/nonexistent", headers=h(get_token()))
|
|
results.append(check("不存在路由返回 404", r.status_code == 404, f"HTTP {r.status_code}"))
|
|
|
|
r = requests.get(f"{BASE_URL}/api/topics/99999", headers=h(get_token()))
|
|
results.append(check("不存在资源返回 404", r.status_code == 404, f"HTTP {r.status_code}"))
|
|
|
|
r = requests.post(f"{BASE_URL}/api/topics", headers=h(get_token()), json={})
|
|
results.append(check("空数据创建返回验证错误", r.status_code == 422, f"HTTP {r.status_code}"))
|
|
|
|
r = requests.post(f"{BASE_URL}/api/topics", headers=h(get_token()), json={"title": ""})
|
|
results.append(check("空标题返回验证错误", r.status_code == 422, f"HTTP {r.status_code}"))
|
|
|
|
section("📄 内容安全")
|
|
token = get_token()
|
|
r = requests.post(f"{BASE_URL}/api/topics", headers=h(token), json={
|
|
"title": "<script>alert('xss')</script>测试",
|
|
"field_id": 1,
|
|
"content": "<script>alert('xss')</script>"
|
|
})
|
|
results.append(check("含 HTML 的内容可创建", r.ok, f"HTTP {r.status_code}"))
|
|
if r.ok:
|
|
new_id = r.json().get("id")
|
|
if new_id:
|
|
r2 = requests.delete(f"{BASE_URL}/api/topics/{new_id}", headers=h(token))
|
|
results.append(check("清理测试数据", r2.ok or r2.status_code == 404))
|
|
|
|
section("🔄 幂等性")
|
|
payload = {"title": "幂等测试", "field_id": 1}
|
|
r1 = requests.post(f"{BASE_URL}/api/topics", headers=h(token), json=payload)
|
|
r2 = requests.post(f"{BASE_URL}/api/topics", headers=h(token), json=payload)
|
|
results.append(check("重复创建不报错", r1.ok and r2.ok, f"第1次:{r1.status_code} 第2次:{r2.status_code}"))
|
|
if r1.ok:
|
|
del_id = r1.json().get("id")
|
|
if del_id:
|
|
requests.delete(f"{BASE_URL}/api/topics/{del_id}", headers=h(token))
|
|
if r2.ok and r2.json().get("id") != (r1.json().get("id") if r1.ok else None):
|
|
del_id2 = r2.json().get("id")
|
|
if del_id2:
|
|
requests.delete(f"{BASE_URL}/api/topics/{del_id2}", headers=h(token))
|
|
|
|
print(f"\n{'='*60}")
|
|
passed = sum(results)
|
|
total = len(results)
|
|
print(f"测试结果: {passed}/{total} 通过 ({passed*100//total}%)")
|
|
print("=" * 60)
|
|
return 0 if passed == total else 1
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|