mirror of
https://github.com/ZHANGTIANYAO1/teamspeak-music-bot.git
synced 2026-10-02 13:02:49 +08:00
fix(guest): deny favorites + auth-status reads to guests; UI polish
Consolidated fix wave from the final whole-branch review of guest mode. - FIX 1 (critical): gate /api/favorites mount with requireNotGuest — the router keys off req.user.id (shared __guest__ principal), so guests could read/write a shared favorites bucket. Added focused guest-deny tests. - FIX 2: gate GET /api/auth/status and /api/auth/qrcode/status with requireNotGuest so config reads no longer leak to guests. - FIX 3: requireAuthInline in createSessionRouter now rejects guest sessions with 401 once guest mode is disabled (mirrors createRequireAuth), so /me stops returning guest data after an admin disables the feature. - FIX 4: Login guest button now sits BELOW the card (auth-page flex-direction column + guest-btn width 360px) instead of beside it. - FIX 5: mobile mini-player transport buttons in App.vue are now per-button gated for guests (prev/play/next/mode/volume), mirroring Player.vue. - FIX 6: refreshed stale "gated on player.control" seek comments in Player.vue and relabeled the now-stale quality-GET test. npm test: 354/354 pass. npm run build: tsc + vue-tsc + vite all green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
e47fc76529
commit
f142c514cd
8 files changed
+113
-12
No files matched your search
@@ -6,6 +6,8 @@ import { createPlayerRouter } from "./player.js";
|
||||
import { createBotRouter } from "./bot.js";
|
||||
import { createAuthRouter } from "./auth.js";
|
||||
import { createMusicRouter } from "./music.js";
|
||||
import { createFavoritesRouter } from "./favorites.js";
|
||||
import { requireNotGuest } from "../middleware/requireNotGuest.js";
|
||||
|
||||
const logger = pino({ level: "silent" });
|
||||
|
||||
@@ -204,7 +206,7 @@ describe("permission enforcement on action routes", () => {
|
||||
expect(res.status).not.toBe(403);
|
||||
});
|
||||
|
||||
it("GET /api/music/quality not gated", async () => {
|
||||
it("GET /api/music/quality readable by members, denied to guests", async () => {
|
||||
const app = makeApp(member([], "all"));
|
||||
const res = await request(app).get("/api/music/quality");
|
||||
expect(res.status).not.toBe(403);
|
||||
@@ -215,6 +217,12 @@ describe("permission enforcement on action routes", () => {
|
||||
const res = await request(app).get("/api/bot");
|
||||
expect(res.status).not.toBe(403);
|
||||
});
|
||||
|
||||
it("GET /api/auth/status and /api/auth/qrcode/status are 403 for guests", async () => {
|
||||
const app = makeApp(guest());
|
||||
expect((await request(app).get("/api/auth/status")).status).toBe(403);
|
||||
expect((await request(app).get("/api/auth/qrcode/status?key=k")).status).toBe(403);
|
||||
});
|
||||
});
|
||||
|
||||
describe("admin bypasses every gate", () => {
|
||||
@@ -368,3 +376,48 @@ describe("guest enforcement on player routes", () => {
|
||||
expect((await request(m).post(`/api/player/${ALLOWED_BOT}/add-song`).send({ song: SONG })).status).not.toBe(403);
|
||||
});
|
||||
});
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Favorites are member-only: the router keys everything off req.user.id and
|
||||
// all guests share the __guest__ principal, so a guest must never reach it.
|
||||
// server.ts gates the mount with requireNotGuest; we mirror that mount here
|
||||
// and assert a guest gets 403 (the requireNotGuest guard runs before any
|
||||
// handler, so the fake database is never touched).
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
function makeFavoritesApp(user: any) {
|
||||
const app = express();
|
||||
app.use(express.json());
|
||||
app.use((req, _res, next) => { (req as any).user = user; next(); });
|
||||
const fakeDb = {
|
||||
getFavorites: () => [],
|
||||
addFavorite: () => {},
|
||||
removeFavorite: () => {},
|
||||
isFavorited: () => false,
|
||||
} as any;
|
||||
app.use("/api/favorites", requireNotGuest, createFavoritesRouter(fakeDb, logger));
|
||||
return app;
|
||||
}
|
||||
|
||||
describe("favorites are denied to guests", () => {
|
||||
it("403 for a guest on GET /api/favorites", async () => {
|
||||
const app = makeFavoritesApp(guest());
|
||||
expect((await request(app).get("/api/favorites")).status).toBe(403);
|
||||
});
|
||||
|
||||
it("403 for a guest on GET /api/favorites/check", async () => {
|
||||
const app = makeFavoritesApp(guest());
|
||||
expect((await request(app).get("/api/favorites/check?platform=netease&playlistId=x")).status).toBe(403);
|
||||
});
|
||||
|
||||
it("403 for a guest on POST /api/favorites", async () => {
|
||||
const app = makeFavoritesApp(guest());
|
||||
const res = await request(app).post("/api/favorites").send({ platform: "netease", playlistId: "x", name: "n" });
|
||||
expect(res.status).toBe(403);
|
||||
});
|
||||
|
||||
it("NOT 403 for a member on GET /api/favorites", async () => {
|
||||
const app = makeFavoritesApp(member([], "all"));
|
||||
expect((await request(app).get("/api/favorites")).status).not.toBe(403);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user