feat: StarLight 第三方登录 + 安全加固 + 循环池 + 热配置
功能: - StarLight Yggdrasil 第三方登录(后端中转,accessToken 不落地) - 管理员可视化权限管理(用户列表 + 一键授予/移出) - 设置页热配置(11 项可编辑,立即生效) - 循环池(每流独立手动歌单,队列空时随机不重复抽取) - 登录页统一主站浅色风格 - 全站改名「Starlight专属电台」 - 删除关于页 安全: - 全局 CSRF 防护(双提交 Cookie) - 登录限流防 XFF 伪造、错误信息脱敏 - 权限中间件 requireAdminForWrites(读放行/写 admin) - 密码哈希存储(scrypt/sha256) - SSRF 防护(封面下载域名白名单) - 空 catch 加日志、SSE 连接上限 修复: - 多角色账号 selectedProfile 缺失 - 普通用户越权删歌(V4) - streams 写操作越权(V9) - 设置页布局溢出 测试:38 项全绿(api16 / e2e17 / write5)
This commit is contained in:
1 parent
5066f32fa4
commit
f0fe50e484
29 files changed
+1703
-315
No files matched your search
+11
-1
@@ -1,6 +1,8 @@
|
||||
import urllib.request, urllib.error, http.cookiejar, json, sys, time
|
||||
|
||||
BASE = "http://127.0.0.1:3000"
|
||||
import os
|
||||
TEST_PASSWORD = os.environ.get("TEST_PASSWORD", "123test")
|
||||
|
||||
def opener_with_cookies():
|
||||
cj = http.cookiejar.CookieJar()
|
||||
@@ -12,6 +14,14 @@ def call(op, path, method="GET", data=None):
|
||||
req = urllib.request.Request(url, data=body, method=method)
|
||||
if body:
|
||||
req.add_header("Content-Type", "application/json")
|
||||
if method.upper() not in ("GET","HEAD","OPTIONS"):
|
||||
for c in op.handlers:
|
||||
cj = getattr(c, "cookiejar", None)
|
||||
if cj:
|
||||
for ck in cj:
|
||||
if ck.name == "mr_csrf":
|
||||
req.add_header("X-CSRF-Token", ck.value); break
|
||||
break
|
||||
try:
|
||||
r = op.open(req, timeout=10)
|
||||
return r.status, r.read()
|
||||
@@ -30,7 +40,7 @@ st, body = call(anon, "/login"); check("登录页200", st == 200, f"got {st}")
|
||||
st, body = call(anon, "/"); check("未登录/=登录页", st == 200 and b"loginForm" in body, f"got {st}")
|
||||
st, _ = call(anon, "/index.html"); check("未登录index.html=登录页", st == 200 and b"loginForm" in _, f"got {st}")
|
||||
st, _ = call(auth, "/api/auth/login", "POST", {"password": "wrong"}); check("错密码401", st == 401, f"got {st}")
|
||||
st, body = call(auth, "/api/auth/login", "POST", {"password": "test123"}); check("登录成功", st == 200 and json.loads(body).get("ok"), f"got {st}")
|
||||
st, body = call(auth, "/api/auth/login", "POST", {"password": TEST_PASSWORD}); check("登录成功", st == 200 and json.loads(body).get("ok"), f"got {st}")
|
||||
|
||||
# 资源与流
|
||||
st, body = call(auth, "/api/resources"); d = json.loads(body)
|
||||
|
||||
Reference in new issue
Block a user