mirror of
https://github.com/ZHANGTIANYAO1/teamspeak-music-bot.git
synced 2026-10-01 20:42:50 +08:00
feat(perm): enforce capabilities + bot access on action routes
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
696b224f8d
commit
cd6f2c6078
6 files changed
+287
-39
No files matched your search
+24
-21
@@ -4,6 +4,7 @@ import type { BotDatabase } from "../../data/database.js";
|
||||
import type { MusicProvider } from "../../music/provider.js";
|
||||
import type { Logger } from "../../logger.js";
|
||||
import { parseCommand } from "../../bot/commands.js";
|
||||
import { requirePermission, requireBotAccess } from "../middleware/requirePermission.js";
|
||||
|
||||
export function createPlayerRouter(
|
||||
botManager: BotManager,
|
||||
@@ -25,6 +26,8 @@ export function createPlayerRouter(
|
||||
next();
|
||||
});
|
||||
|
||||
router.use("/:botId", requireBotAccess("botId"));
|
||||
|
||||
/** Map API platform string to the corresponding command flag. */
|
||||
const platformFlag = (platform: unknown): string => {
|
||||
if (platform === "bilibili") return "-b";
|
||||
@@ -33,7 +36,7 @@ export function createPlayerRouter(
|
||||
return "";
|
||||
};
|
||||
|
||||
router.post("/:botId/play", async (req, res) => {
|
||||
router.post("/:botId/play", requirePermission("player.control"), async (req, res) => {
|
||||
try {
|
||||
const bot = (req as any).bot;
|
||||
const { query, platform } = req.body;
|
||||
@@ -53,7 +56,7 @@ export function createPlayerRouter(
|
||||
}
|
||||
});
|
||||
|
||||
router.post("/:botId/add", async (req, res) => {
|
||||
router.post("/:botId/add", requirePermission("player.queue"), async (req, res) => {
|
||||
try {
|
||||
const bot = (req as any).bot;
|
||||
const { query, platform } = req.body;
|
||||
@@ -80,14 +83,14 @@ export function createPlayerRouter(
|
||||
}
|
||||
};
|
||||
|
||||
router.post("/:botId/pause", simpleCommand("!pause"));
|
||||
router.post("/:botId/resume", simpleCommand("!resume"));
|
||||
router.post("/:botId/next", simpleCommand("!next"));
|
||||
router.post("/:botId/prev", simpleCommand("!prev"));
|
||||
router.post("/:botId/stop", simpleCommand("!stop"));
|
||||
router.post("/:botId/clear", simpleCommand("!clear"));
|
||||
router.post("/:botId/pause", requirePermission("player.control"), simpleCommand("!pause"));
|
||||
router.post("/:botId/resume", requirePermission("player.control"), simpleCommand("!resume"));
|
||||
router.post("/:botId/next", requirePermission("player.control"), simpleCommand("!next"));
|
||||
router.post("/:botId/prev", requirePermission("player.control"), simpleCommand("!prev"));
|
||||
router.post("/:botId/stop", requirePermission("player.control"), simpleCommand("!stop"));
|
||||
router.post("/:botId/clear", requirePermission("player.queue"), simpleCommand("!clear"));
|
||||
|
||||
router.post("/:botId/volume", async (req, res) => {
|
||||
router.post("/:botId/volume", requirePermission("player.control"), async (req, res) => {
|
||||
try {
|
||||
const bot = (req as any).bot;
|
||||
const { volume } = req.body;
|
||||
@@ -115,7 +118,7 @@ export function createPlayerRouter(
|
||||
|
||||
const VALID_MODES = new Set(["seq", "loop", "random", "rloop"]);
|
||||
|
||||
router.post("/:botId/mode", async (req, res) => {
|
||||
router.post("/:botId/mode", requirePermission("player.control"), async (req, res) => {
|
||||
try {
|
||||
const bot = (req as any).bot;
|
||||
const { mode } = req.body;
|
||||
@@ -140,7 +143,7 @@ export function createPlayerRouter(
|
||||
});
|
||||
|
||||
// Seek to position
|
||||
router.post("/:botId/seek", async (req, res) => {
|
||||
router.post("/:botId/seek", requirePermission("player.control"), async (req, res) => {
|
||||
try {
|
||||
const bot = (req as any).bot;
|
||||
const { position } = req.body; // seconds
|
||||
@@ -164,7 +167,7 @@ export function createPlayerRouter(
|
||||
res.json({ queue: bot.getQueue(), status: bot.getStatus() });
|
||||
});
|
||||
|
||||
router.delete("/:botId/queue/:index", async (req, res) => {
|
||||
router.delete("/:botId/queue/:index", requirePermission("player.queue"), async (req, res) => {
|
||||
try {
|
||||
const bot = (req as any).bot;
|
||||
const cmd = parseCommand(`!remove ${req.params.index}`, "!")!;
|
||||
@@ -176,7 +179,7 @@ export function createPlayerRouter(
|
||||
});
|
||||
|
||||
// Jump to a specific index in the queue (without clearing it)
|
||||
router.post("/:botId/play-at", async (req, res) => {
|
||||
router.post("/:botId/play-at", requirePermission("player.control"), async (req, res) => {
|
||||
try {
|
||||
const bot = (req as any).bot;
|
||||
const { index } = req.body;
|
||||
@@ -210,7 +213,7 @@ export function createPlayerRouter(
|
||||
}
|
||||
});
|
||||
|
||||
router.post("/:botId/playlist", async (req, res) => {
|
||||
router.post("/:botId/playlist", requirePermission("player.queue"), async (req, res) => {
|
||||
try {
|
||||
const bot = (req as any).bot;
|
||||
const { playlistId, platform } = req.body;
|
||||
@@ -227,7 +230,7 @@ export function createPlayerRouter(
|
||||
|
||||
// Play a playlist by ID — stores metadata only, resolves URL for first song
|
||||
// Respects current play mode (random = pick random first song)
|
||||
router.post("/:botId/play-playlist", async (req, res) => {
|
||||
router.post("/:botId/play-playlist", requirePermission("player.control"), async (req, res) => {
|
||||
try {
|
||||
const bot = (req as any).bot;
|
||||
const { playlistId, platform } = req.body;
|
||||
@@ -314,7 +317,7 @@ export function createPlayerRouter(
|
||||
});
|
||||
|
||||
// Play an album by ID — mirrors play-playlist but calls getAlbumSongs
|
||||
router.post("/:botId/play-album", async (req, res) => {
|
||||
router.post("/:botId/play-album", requirePermission("player.control"), async (req, res) => {
|
||||
try {
|
||||
const bot = (req as any).bot;
|
||||
const { albumId, platform } = req.body;
|
||||
@@ -386,7 +389,7 @@ export function createPlayerRouter(
|
||||
});
|
||||
|
||||
// Play a single song by ID — resolves URL on demand
|
||||
router.post("/:botId/play-song", async (req, res) => {
|
||||
router.post("/:botId/play-song", requirePermission("player.control"), async (req, res) => {
|
||||
try {
|
||||
const bot = (req as any).bot;
|
||||
const { song } = req.body;
|
||||
@@ -414,7 +417,7 @@ export function createPlayerRouter(
|
||||
|
||||
// Insert a single song to play right after the current one.
|
||||
// If nothing is playing, behaves like /play-song (start immediately).
|
||||
router.post("/:botId/play-next-song", async (req, res) => {
|
||||
router.post("/:botId/play-next-song", requirePermission("player.control"), async (req, res) => {
|
||||
try {
|
||||
const bot = (req as any).bot;
|
||||
const { song } = req.body;
|
||||
@@ -452,7 +455,7 @@ export function createPlayerRouter(
|
||||
}
|
||||
});
|
||||
|
||||
router.post("/:botId/add-song", async (req, res) => {
|
||||
router.post("/:botId/add-song", requirePermission("player.queue"), async (req, res) => {
|
||||
try {
|
||||
const bot = (req as any).bot;
|
||||
const { song } = req.body;
|
||||
@@ -480,7 +483,7 @@ export function createPlayerRouter(
|
||||
});
|
||||
|
||||
// Add a song to queue by ID — metadata only
|
||||
router.post("/:botId/add-by-id", async (req, res) => {
|
||||
router.post("/:botId/add-by-id", requirePermission("player.queue"), async (req, res) => {
|
||||
try {
|
||||
const bot = (req as any).bot;
|
||||
const { songId, platform } = req.body;
|
||||
@@ -518,7 +521,7 @@ export function createPlayerRouter(
|
||||
res.json(bot.getProfileManager().getConfig());
|
||||
});
|
||||
|
||||
router.put("/:botId/profile", (req, res) => {
|
||||
router.put("/:botId/profile", requirePermission("bot.manage"), (req, res) => {
|
||||
try {
|
||||
const bot = (req as any).bot;
|
||||
const pm = bot.getProfileManager();
|
||||
|
||||
Reference in new issue
Block a user