- Monorepo: NestJS API (Fastify) + React web (antd/ProComponents) + shared packages - PostgreSQL/Prisma (unified resources, relations graph, audit, events, jobs) - Auth/RBAC/workspace isolation, credential vault (AES-256-GCM) - Servers/SSH, Docker discovery & lifecycle, Job Center - Websites & deployments (git provider credential clone, env, health verification) - Domains/DNS (Cloudflare adapter), certificates (TLS probe), monitoring - Automation (cron/event/webhook HMAC + notifications), AI Gateway, MCP (29 tools) - AI chat window (LLM function-calling + rules fallback, SSE streaming, approvals) - Notes: Vditor WYSIWYG markdown editor, non-blocking autosave - Tests: 35 unit/security tests; UI audit clean (desktop+mobile, deep links)
59 lines
2.2 KiB
TypeScript
59 lines
2.2 KiB
TypeScript
/** JWT 签发/校验单元测试(@devos/auth) */
|
||
import { describe, test, expect } from "bun:test";
|
||
import { signJwt, verifyJwt, hashPassword, verifyPassword } from "../packages/auth/src/index";
|
||
|
||
const SECRET = "test-secret";
|
||
|
||
describe("JWT", () => {
|
||
test("签发并校验合法令牌", () => {
|
||
const token = signJwt({ sub: "u1", email: "a@b.c", wid: "w1" }, SECRET, { nowSec: 1000, expiresInSec: 3600 });
|
||
const result = verifyJwt(token, SECRET, 2000);
|
||
expect(result.ok).toBe(true);
|
||
if (result.ok) {
|
||
expect(result.payload.sub).toBe("u1");
|
||
expect(result.payload.wid).toBe("w1");
|
||
expect(result.payload.exp).toBe(4600);
|
||
}
|
||
});
|
||
|
||
test("过期令牌被拒绝", () => {
|
||
const token = signJwt({ sub: "u1", email: "a@b.c", wid: null }, SECRET, { nowSec: 1000, expiresInSec: 100 });
|
||
const result = verifyJwt(token, SECRET, 2000);
|
||
expect(result.ok).toBe(false);
|
||
if (!result.ok) expect(result.reason).toBe("EXPIRED");
|
||
});
|
||
|
||
test("篡改签名被拒绝", () => {
|
||
const token = signJwt({ sub: "u1", email: "a@b.c", wid: null }, SECRET);
|
||
const parts = token.split(".");
|
||
const tampered = `${parts[0]}.${parts[1]}.AAAA${parts[2].slice(4)}`;
|
||
expect(verifyJwt(tampered, SECRET).ok).toBe(false);
|
||
});
|
||
|
||
test("错误密钥被拒绝", () => {
|
||
const token = signJwt({ sub: "u1", email: "a@b.c", wid: null }, SECRET);
|
||
expect(verifyJwt(token, "other-secret").ok).toBe(false);
|
||
});
|
||
|
||
test("alg 混淆攻击被拒绝(仅接受 HS256)", () => {
|
||
const forgedHeader = Buffer.from(JSON.stringify({ alg: "none" })).toString("base64url");
|
||
const payload = Buffer.from(JSON.stringify({ sub: "u1", exp: 9999999999 })).toString("base64url");
|
||
const forged = `${forgedHeader}.${payload}.`;
|
||
expect(verifyJwt(forged, SECRET).ok).toBe(false);
|
||
});
|
||
|
||
test("畸形令牌被拒绝", () => {
|
||
expect(verifyJwt("abc", SECRET).ok).toBe(false);
|
||
expect(verifyJwt("a.b.c", SECRET).ok).toBe(false);
|
||
});
|
||
});
|
||
|
||
describe("Password", () => {
|
||
test("哈希并校验密码", async () => {
|
||
const hash = await hashPassword("MyPassword123!");
|
||
expect(hash).not.toContain("MyPassword123!");
|
||
expect(await verifyPassword("MyPassword123!", hash)).toBe(true);
|
||
expect(await verifyPassword("wrong", hash)).toBe(false);
|
||
});
|
||
});
|