mirror of
https://github.com/ZHANGTIANYAO1/teamspeak-music-bot.git
synced 2026-10-11 09:22:49 +08:00
feat(web): add API-key authentication for the REST API
- api_keys table + hashed key store (src/data/api-keys.ts), tsmb_-prefixed plaintext shown once, per-user cap of 20, lastUsedAt tracking - requireAuth accepts Authorization: Bearer / X-API-Key headers as an alternative to the session cookie; key inherits the owner user's role/capabilities/bot scope - csrf origin check skipped for key-only requests (no ambient credentials); requests that also carry the session cookie stay gated - /api/keys management endpoints (session-only, guests excluded, keys themselves rejected) with audit logging - user deletion / password reset cascade-revoke the user's keys - Settings page: API key management section (create/copy-once/revoke) - docs: README section + full endpoint reference in docs/API.md
This commit is contained in:
1 parent
2ea02f54d9
commit
aab8a004ae
16 files changed
+1272
-7
No files matched your search
@@ -70,4 +70,28 @@ describe("csrfOriginCheck middleware", () => {
|
||||
expect(res.status).toBe(403);
|
||||
expect(res.body).toEqual({ error: "bad origin" });
|
||||
});
|
||||
|
||||
// API-key clients authenticate via a header the browser never attaches
|
||||
// automatically, so CSRF cannot abuse them — the origin check is skipped.
|
||||
it("allows POST with an X-API-Key header and no session cookie", async () => {
|
||||
const res = await request(app).post("/").set("X-API-Key", "tsmb_abc");
|
||||
expect(res.status).toBe(200);
|
||||
});
|
||||
|
||||
it("allows POST with an Authorization: Bearer key and no session cookie", async () => {
|
||||
const res = await request(app).post("/").set("Authorization", "Bearer tsmb_abc");
|
||||
expect(res.status).toBe(200);
|
||||
});
|
||||
|
||||
it("does NOT skip the origin check when a session cookie rides along with an API key", async () => {
|
||||
// An attacker page can set arbitrary headers while the victim's cookie is
|
||||
// attached ambiently — the cookie keeps the request under the gate.
|
||||
const res = await request(app)
|
||||
.post("/")
|
||||
.set("Host", "example.com")
|
||||
.set("Origin", "https://evil.com")
|
||||
.set("Cookie", "tsmb_session=whatever")
|
||||
.set("X-API-Key", "tsmb_abc");
|
||||
expect(res.status).toBe(403);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user