import test from "node:test"; import assert from "node:assert/strict"; import { createHmac } from "node:crypto"; import { createHttpServer } from "../src/app/http.ts"; import { loadConfig } from "../src/config.ts"; import { createTotpSecret, encryptSecret, issueAccessToken, verifyAccessToken } from "../src/shared/auth.ts"; import { createStore } from "../src/store.ts"; function config(role = "operator") { return { host: "127.0.0.1", port: 0, accessTokenSecret: "test-secret-for-security-tests", accessTokenTtlSeconds: 900, refreshCookieName: "refresh", adminEmail: "admin@example.com", adminPassword: "change-me-now", adminMfaRequired: false, userMfaRequired: false, adminRole: role }; } test("ordinary-user verification enhancements default to disabled", () => { const config = loadConfig({ NODE_ENV: "development", MIRAGENFLOW_ACCESS_TOKEN_SECRET: "default-test-secret" }); assert.equal(config.adminMfaRequired, false); assert.equal(config.userMfaRequired, false); assert.equal(config.userVerificationRequired, false); assert.equal(config.captchaRequired, false); assert.equal(config.adminAccounts?.[0]?.mfaRequired, false); }); test("cookie security can be explicitly disabled for an HTTP reverse proxy", () => { const productionEnv = { NODE_ENV: "production", MIRAGENFLOW_ACCESS_TOKEN_SECRET: "a-production-secret-that-is-long-enough", MIRAGENFLOW_ADMIN_PASSWORD: "a-production-admin-password", MIRAGENFLOW_ADMIN_MFA_SECRET: "JBSWY3DPEHPK3PXP", MIRAGENFLOW_CHANNEL_ENCRYPTION_KEY: "a-production-channel-key", MIRAGENFLOW_PERSISTENCE_ADAPTER: "postgres", DATABASE_URL: "postgres://example", MIRAGENFLOW_QUEUE_ADAPTER: "redis", REDIS_URL: "redis://example", }; const productionDefaults = loadConfig(productionEnv); assert.equal(productionDefaults.cookieSecure, true); assert.equal(loadConfig({ ...productionEnv, MIRAGENFLOW_COOKIE_SECURE: "false" }).cookieSecure, false); assert.equal(loadConfig({ NODE_ENV: "development", MIRAGENFLOW_ACCESS_TOKEN_SECRET: "default-test-secret", MIRAGENFLOW_COOKIE_SECURE: "true" }).cookieSecure, true); }); function totpCode(secret: string, now = Date.now()) { const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; let buffer = 0; let bits = 0; const bytes: number[] = []; for (const character of secret) { const value = alphabet.indexOf(character); if (value < 0) continue; buffer = (buffer << 5) | value; bits += 5; if (bits >= 8) { bytes.push((buffer >>> (bits - 8)) & 255); bits -= 8; } } const key = Buffer.from(bytes); const message = Buffer.alloc(8); message.writeBigInt64BE(BigInt(Math.floor(now / 30_000))); const digest = createHmac("sha1", key).update(message).digest(); const offset = digest[digest.length - 1] & 15; const value = ((digest[offset] & 127) << 24) | (digest[offset + 1] << 16) | (digest[offset + 2] << 8) | digest[offset + 3]; return String(value % 1_000_000).padStart(6, "0"); } test("CAPTCHA challenge is hashed, bound, retry-limited, and one-time", async () => { const store = createStore(); const server = createHttpServer(store, { ...config(), captchaRequired: true }); await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve)); const address = server.address(); assert.ok(address && typeof address !== "string"); const base = `http://127.0.0.1:${address.port}`; const email = "captcha@example.com"; const deviceId = "captcha-device"; try { const challengeResponse = await fetch(`${base}/api/v1/auth/challenge`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ action: "register", target: email, deviceId }) }); assert.equal(challengeResponse.status, 200); const challenge = (await challengeResponse.json() as { data: { challengeId: string; question: string } }).data; const numbers = challenge.question.match(/(\d+) \+ (\d+)/); assert.ok(numbers); const answer = String(Number(numbers[1]) + Number(numbers[2])); const baseBody = { email, password: "password123", deviceId, captchaChallengeId: challenge.challengeId }; const wrong = await fetch(`${base}/api/v1/auth/register`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ ...baseBody, captchaAnswer: "0" }) }); assert.equal(wrong.status, 422); const registered = await fetch(`${base}/api/v1/auth/register`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ ...baseBody, captchaAnswer: answer }) }); assert.equal(registered.status, 201); const reused = await fetch(`${base}/api/v1/auth/register`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ ...baseBody, email: "captcha-second@example.com", captchaAnswer: answer }) }); assert.equal(reused.status, 422); assert.equal(store.captchaChallenges.get(challenge.challengeId)?.consumedAt !== undefined, true); } finally { await new Promise((resolve, reject) => server.close((error) => error ? reject(error) : resolve())); } }); test("administrator MFA retry is exempt only after a valid CAPTCHA-bound challenge", async () => { const secret = "JBSWY3DPEHPK3PXP"; const store = createStore(); const server = createHttpServer(store, { ...config(), captchaRequired: true, adminMfaRequired: true, adminMfaSecret: secret }); await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve)); const address = server.address(); assert.ok(address && typeof address !== "string"); const base = `http://127.0.0.1:${address.port}`; try { const challengeResponse = await fetch(`${base}/api/v1/auth/challenge`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ action: "admin-login", target: "admin@example.com", deviceId: "admin-browser" }) }); const challenge = (await challengeResponse.json() as { data: { challengeId: string; question: string } }).data; const numbers = challenge.question.match(/(\d+) \+ (\d+)/); assert.ok(numbers); const answer = String(Number(numbers[1]) + Number(numbers[2])); const first = await fetch(`${base}/api/v1/admin/auth/login`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ email: "admin@example.com", password: "change-me-now", deviceId: "admin-browser", captchaChallengeId: challenge.challengeId, captchaAnswer: answer }) }); const firstData = (await first.json() as { data: { mfaRequired?: boolean; challengeId?: string } }).data; assert.equal(first.status, 200); assert.equal(firstData.mfaRequired, true); assert.ok(firstData.challengeId); const second = await fetch(`${base}/api/v1/admin/auth/login`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ email: "admin@example.com", password: "change-me-now", deviceId: "admin-browser", challengeId: firstData.challengeId, mfaCode: totpCode(secret) }) }); const secondData = (await second.json() as { data: { accessToken?: string } }).data; assert.equal(second.status, 200); assert.ok(secondData.accessToken); } finally { await new Promise((resolve, reject) => server.close((error) => error ? reject(error) : resolve())); } }); test("refresh restores a missing legacy CSRF cookie without weakening business writes", async () => { const { store, server, base } = await start("super_admin"); try { const login = await fetch(`${base}/api/v1/admin/auth/login`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ email: "admin@example.com", password: "change-me-now" }) }); assert.equal(login.status, 200); const setCookies = login.headers.getSetCookie(); const refresh = setCookies.find((value) => value.startsWith("refresh_admin=")); assert.ok(refresh); const legacyCookie = refresh.split(";", 1)[0]; const refreshed = await fetch(`${base}/api/v1/admin/auth/refresh`, { method: "POST", headers: { cookie: `${legacyCookie}` } }); assert.equal(refreshed.status, 200); const restoredCookies = refreshed.headers.getSetCookie(); const nextRefresh = restoredCookies.find((value) => value.startsWith("refresh_admin=")); assert.ok(nextRefresh); assert.equal(restoredCookies.some((value) => value.startsWith("miragenflow_csrf_admin=") && !value.includes("HttpOnly")), true); const refreshedPayload = await refreshed.json() as { data: { accessToken: string } }; const protectedWrite = await fetch(`${base}/api/v1/admin/settings`, { method: "PATCH", headers: { cookie: `${nextRefresh!.split(";", 1)[0]}`, authorization: `Bearer ${refreshedPayload.data.accessToken}`, "content-type": "application/json", "idempotency-key": "legacy-csrf-write" }, body: JSON.stringify({}) }); assert.equal(protectedWrite.status, 403); } finally { await new Promise((resolve, reject) => server.close((error) => error ? reject(error) : resolve())); } }); async function start(role = "operator") { const store = createStore(); const server = createHttpServer(store, config(role)); await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve)); const address = server.address(); assert.ok(address && typeof address !== "string"); return { store, server, base: `http://127.0.0.1:${address.port}` }; } test("admin RBAC rejects finance access and redacts support channel internals", async () => { const { store, server, base } = await start("support"); try { store.channels[0].providerName = "internal-provider"; store.channels[0].models[0].requestModelId = "internal-model"; store.channels[0].baseUrl = "https://provider.example.com"; const login = await fetch(`${base}/api/v1/admin/auth/login`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ email: "admin@example.com", password: "change-me-now" }) }); const loginPayload = await login.json() as { data: { accessToken: string } }; assert.ok(loginPayload.data.accessToken); const auth = { authorization: `Bearer ${loginPayload.data.accessToken}` }; const finance = await fetch(`${base}/api/v1/admin/billing/ledger`, { headers: auth }); assert.equal(finance.status, 403); const channels = await fetch(`${base}/api/v1/admin/channels`, { headers: auth }); assert.equal(channels.status, 200); const payload = await channels.json() as { data: { items: Array> } }; assert.equal(payload.data.items[0].providerModelId, undefined); assert.equal(payload.data.items[0].baseUrl, undefined); } finally { await new Promise((resolve, reject) => server.close((error) => error ? reject(error) : resolve())); } }); test("payment provider credentials are encrypted and redacted", async () => { const { store, server, base } = await start("super_admin"); try { const login = await fetch(`${base}/api/v1/admin/auth/login`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ email: "admin@example.com", password: "change-me-now" }) }); const loginPayload = await login.json() as { data: { accessToken: string } }; const auth = { authorization: `Bearer ${loginPayload.data.accessToken}`, "content-type": "application/json", "idempotency-key": "payment-provider-create" }; const created = await fetch(`${base}/api/v1/admin/payment-providers`, { method: "POST", headers: auth, body: JSON.stringify({ id: "secure-adapter", name: "Secure adapter", mode: "live", secret: "payment-secret-value" }) }); assert.equal(created.status, 201); const createdPayload = await created.json() as { data: { item: Record } }; assert.equal(createdPayload.data.item.secretRef, undefined); assert.equal(createdPayload.data.item.secretConfigured, true); const stored = store.paymentProviders.get("secure-adapter"); assert.ok(typeof stored?.secretRef === "string"); assert.notEqual(stored?.secretRef, "payment-secret-value"); const listed = await fetch(`${base}/api/v1/admin/payment-providers`, { headers: { authorization: `Bearer ${loginPayload.data.accessToken}` } }); const listedPayload = await listed.json() as { data: { items: Array> } }; assert.equal(listedPayload.data.items[0].secretRef, undefined); assert.equal(listedPayload.data.items[0].secret, undefined); } finally { await new Promise((resolve, reject) => server.close((error) => error ? reject(error) : resolve())); } }); test("OpenAI image channel creation does not probe implicitly and explicit probing uses Bearer auth", async () => { const { store, server, base } = await start("super_admin"); const previousFetch = globalThis.fetch; const probeRequests: Array<{ method: string; authorization: string | null; url: string }> = []; try { const login = await fetch(`${base}/api/v1/admin/auth/login`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ email: "admin@example.com", password: "change-me-now" }) }); const loginPayload = await login.json() as { data: { accessToken: string } }; globalThis.fetch = async (input, init) => { const url = String(input); if (url.startsWith("https://1.1.1.1/")) { probeRequests.push({ url, method: init?.method || "GET", authorization: new Headers(init?.headers).get("authorization") }); return new Response(JSON.stringify({ data: [{ id: "gpt-image-2" }, { id: "gpt-image-2-2k" }] }), { status: 200, headers: { "content-type": "application/json" } }); } return previousFetch(input, init); }; const auth = { authorization: `Bearer ${loginPayload.data.accessToken}`, "content-type": "application/json" }; const created = await fetch(`${base}/api/v1/admin/channels`, { method: "POST", headers: { ...auth, "idempotency-key": "openai-channel-create" }, body: JSON.stringify({ label: "OpenAI 图片渠道", providerType: "openai-images", models: [{ requestModelId: "gpt-image-2", source: "manual", enabled: true }, { requestModelId: "gpt-image-2-2k", source: "manual", enabled: true }], baseUrl: "https://1.1.1.1/v1", secretRef: "k" }) }); assert.equal(created.status, 201); const createdPayload = await created.json() as { data: { item: Record } }; assert.equal(createdPayload.data.item.secretRef, "configured"); assert.equal(createdPayload.data.item.baseUrl, "https://1.1.1.1/v1"); assert.deepEqual(createdPayload.data.item.models, [{ requestModelId: "gpt-image-2", source: "manual", enabled: true }, { requestModelId: "gpt-image-2-2k", source: "manual", enabled: true }]); const channel = store.channels.find((item) => item.id === createdPayload.data.item.id); assert.ok(channel); assert.notEqual(channel.secretRef, "k"); assert.equal(probeRequests.length, 0); const probe = await fetch(`${base}/api/v1/admin/channels/probe`, { method: "POST", headers: { ...auth, "idempotency-key": "openai-channel-probe" }, body: JSON.stringify({ providerType: "openai-images", baseUrl: "https://1.1.1.1/v1", secretRef: "k" }) }); assert.equal(probe.status, 200); assert.equal(probeRequests[0]?.url, "https://1.1.1.1/v1/models"); assert.equal(probeRequests[0]?.method, "GET"); assert.equal(probeRequests[0]?.authorization, "Bearer k"); const invalid = await fetch(`${base}/api/v1/admin/channels`, { method: "POST", headers: { ...auth, "idempotency-key": "openai-channel-http" }, body: JSON.stringify({ label: "不安全渠道", providerType: "openai-images", models: [{ requestModelId: "gpt-image-2", source: "manual", enabled: true }], baseUrl: "http://1.1.1.1/v1", secretRef: "1234567890123456" }) }); assert.equal(invalid.status, 201); assert.equal(store.channels.some((item) => item.label === "不安全渠道"), true); } finally { globalThis.fetch = previousFetch; await new Promise((resolve, reject) => server.close((error) => error ? reject(error) : resolve())); } }); test("admin channel probe reports whether the upstream request was attempted and why it failed", async () => { const { server, base } = await start("super_admin"); const previousFetch = globalThis.fetch; try { const login = await fetch(`${base}/api/v1/admin/auth/login`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ email: "admin@example.com", password: "change-me-now" }) }); const loginPayload = await login.json() as { data: { accessToken: string } }; let upstreamRequest: { method?: string; authorization?: string | null } | undefined; globalThis.fetch = async (input, init) => { if (String(input) === "https://1.1.1.1/v1/models") { upstreamRequest = { method: init?.method, authorization: new Headers(init?.headers).get("authorization") }; return new Response(JSON.stringify({ error: { message: "invalid api key" } }), { status: 401, headers: { "content-type": "application/json" } }); } return previousFetch(input, init); }; const response = await fetch(`${base}/api/v1/admin/channels/probe`, { method: "POST", headers: { authorization: `Bearer ${loginPayload.data.accessToken}`, "content-type": "application/json", "idempotency-key": "channel-probe-failure-details" }, body: JSON.stringify({ providerType: "openai-images", baseUrl: "https://1.1.1.1/v1", secretRef: "short-key" }), }); assert.equal(response.status, 200); const payload = await response.json() as { data: { item: { healthy: boolean; requestAttempted: boolean; requestPath: string; error?: string } } }; assert.equal(payload.data.item.healthy, false); assert.equal(payload.data.item.requestAttempted, true); assert.equal(payload.data.item.requestPath, "/v1/models"); assert.match(payload.data.item.error || "", /API Key/); assert.deepEqual(upstreamRequest, { method: "GET", authorization: "Bearer short-key" }); } finally { globalThis.fetch = previousFetch; await new Promise((resolve, reject) => server.close((error) => error ? reject(error) : resolve())); } }); test("admin channel probe classifies transport causes without exposing credentials", async () => { const { server, base } = await start("super_admin"); const previousFetch = globalThis.fetch; const secret = "transport-secret-value"; try { const login = await fetch(`${base}/api/v1/admin/auth/login`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ email: "admin@example.com", password: "change-me-now" }) }); const loginPayload = await login.json() as { data: { accessToken: string } }; const cases = [ { code: "ECONNREFUSED", text: "拒绝建立连接" }, { code: "ECONNRESET", text: "连接被中断" }, { code: "CERT_HAS_EXPIRED", text: "TLS" }, { code: "UND_ERR_CONNECT_TIMEOUT", text: "超时" }, ]; for (const [index, item] of cases.entries()) { globalThis.fetch = async (input, init) => { if (String(input) === "https://1.1.1.1/v1/models") throw Object.assign(new TypeError("fetch failed"), { cause: { code: item.code } }); return previousFetch(input, init); }; const response = await fetch(`${base}/api/v1/admin/channels/probe`, { method: "POST", headers: { authorization: `Bearer ${loginPayload.data.accessToken}`, "content-type": "application/json", "idempotency-key": `transport-cause-${index}` }, body: JSON.stringify({ providerType: "openai-images", baseUrl: "https://1.1.1.1/v1", secretRef: secret }) }); const payload = await response.json() as { data: { item: { healthy: boolean; requestAttempted: boolean; error?: string } } }; assert.equal(response.status, 200); assert.equal(payload.data.item.healthy, false); assert.equal(payload.data.item.requestAttempted, true); assert.match(payload.data.item.error || "", new RegExp(item.text)); assert.doesNotMatch(payload.data.item.error || "", /transport-secret-value|Bearer/); } } finally { globalThis.fetch = previousFetch; await new Promise((resolve, reject) => server.close((error) => error ? reject(error) : resolve())); } }); test("unsupported generic channel probes do not infer health from a configured key", async () => { const { server, base } = await start("super_admin"); const previousFetch = globalThis.fetch; let upstreamCalls = 0; try { const login = await fetch(`${base}/api/v1/admin/auth/login`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ email: "admin@example.com", password: "change-me-now" }) }); const loginPayload = await login.json() as { data: { accessToken: string } }; globalThis.fetch = async (input, init) => { if (String(input).startsWith("https://generic.example.com/")) upstreamCalls += 1; return previousFetch(input, init); }; const response = await fetch(`${base}/api/v1/admin/channels/probe`, { method: "POST", headers: { authorization: `Bearer ${loginPayload.data.accessToken}`, "content-type": "application/json", "idempotency-key": "generic-channel-probe" }, body: JSON.stringify({ providerType: "generic", baseUrl: "https://generic.example.com/v1", secretRef: "configured-key" }), }); assert.equal(response.status, 200); const payload = await response.json() as { data: { item: { healthy: boolean; requestAttempted: boolean; error?: string } } }; assert.equal(payload.data.item.healthy, false); assert.equal(payload.data.item.requestAttempted, false); assert.match(payload.data.item.error || "", /不支持自动模型列表探活/); assert.equal(upstreamCalls, 0); } finally { globalThis.fetch = previousFetch; await new Promise((resolve, reject) => server.close((error) => error ? reject(error) : resolve())); } }); test("provider probe reports blocked addresses before an upstream request", async () => { const { server, base } = await start("super_admin"); const previousFetch = globalThis.fetch; const previousAllowLocal = process.env.MIRAGENFLOW_ALLOW_LOCAL_PROVIDER_URLS; let upstreamCalls = 0; try { const login = await fetch(`${base}/api/v1/admin/auth/login`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ email: "admin@example.com", password: "change-me-now" }) }); const loginPayload = await login.json() as { data: { accessToken: string } }; process.env.MIRAGENFLOW_ALLOW_LOCAL_PROVIDER_URLS = "false"; globalThis.fetch = async (input, init) => { if (String(input).startsWith("https://127.0.0.1")) upstreamCalls += 1; return previousFetch(input, init); }; const response = await fetch(`${base}/api/v1/admin/channels/probe`, { method: "POST", headers: { authorization: `Bearer ${loginPayload.data.accessToken}`, "content-type": "application/json", "idempotency-key": "dns-channel-probe" }, body: JSON.stringify({ providerType: "openai-images", baseUrl: "https://127.0.0.1/v1", secretRef: "configured-key" }), }); assert.equal(response.status, 200); const payload = await response.json() as { data: { item: { healthy: boolean; requestAttempted: boolean; error?: string } } }; assert.equal(payload.data.item.healthy, false); assert.equal(payload.data.item.requestAttempted, false); assert.match(payload.data.item.error || "", /不允许指向本机/); assert.match(payload.data.item.error || "", /未发起|尚未发起/); assert.equal(upstreamCalls, 0); } finally { globalThis.fetch = previousFetch; if (previousAllowLocal === undefined) delete process.env.MIRAGENFLOW_ALLOW_LOCAL_PROVIDER_URLS; else process.env.MIRAGENFLOW_ALLOW_LOCAL_PROVIDER_URLS = previousAllowLocal; await new Promise((resolve, reject) => server.close((error) => error ? reject(error) : resolve())); } }); test("WebDAV If-Match mismatch returns a conflict before any remote request", async () => { const { store, server, base } = await start(); try { const register = await fetch(`${base}/api/v1/auth/register`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ email: "webdav-conflict@example.com", password: "password123" }) }); const registered = await register.json() as { data: { userId: string; devVerificationCode: string } }; await fetch(`${base}/api/v1/auth/verify-email`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ userId: registered.data.userId, code: registered.data.devVerificationCode }) }); const login = await fetch(`${base}/api/v1/auth/login`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ email: "webdav-conflict@example.com", password: "password123" }) }); const session = await login.json() as { data: { accessToken: string } }; const auth = { authorization: `Bearer ${session.data.accessToken}`, "content-type": "application/json" }; store.webdav.set(registered.data.userId, { userId: registered.data.userId, configured: true, directory: "miragenflow", state: "ready", retentionDays: 30, encryptedUrl: encryptSecret("https://dav.example.com", config().accessTokenSecret) }); store.webdavFiles.set(`${registered.data.userId}:canvas/manifest.json`, { userId: registered.data.userId, path: "canvas/manifest.json", mimeType: "application/json", data: "eA==", checksum: "a".repeat(64), etag: '"remote-v2"', version: 2, updatedAt: new Date().toISOString() }); const response = await fetch(`${base}/api/v1/me/webdav/file`, { method: "PUT", headers: auth, body: JSON.stringify({ path: "canvas/manifest.json", mimeType: "application/json", data: "eA==", ifMatch: '"stale"' }) }); assert.equal(response.status, 409); const payload = await response.json() as { error?: { code?: string } }; assert.equal(payload.error?.code, "VERSION_CONFLICT"); assert.equal([...store.webdavJobs.values()].length, 0); } finally { await new Promise((resolve, reject) => server.close((error) => error ? reject(error) : resolve())); } }); test("WebDAV rejects traversal paths before creating a retry job", async () => { const { store, server, base } = await start(); try { const register = await fetch(`${base}/api/v1/auth/register`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ email: "webdav-path@example.com", password: "password123" }) }); const registered = await register.json() as { data: { userId: string; devVerificationCode: string } }; await fetch(`${base}/api/v1/auth/verify-email`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ userId: registered.data.userId, code: registered.data.devVerificationCode }) }); const login = await fetch(`${base}/api/v1/auth/login`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ email: "webdav-path@example.com", password: "password123" }) }); const session = await login.json() as { data: { accessToken: string } }; store.webdav.set(registered.data.userId, { userId: registered.data.userId, configured: true, directory: "miragenflow", state: "ready", retentionDays: 30, encryptedUrl: encryptSecret("https://dav.example.com", config().accessTokenSecret) }); const response = await fetch(`${base}/api/v1/me/webdav/file`, { method: "PUT", headers: { authorization: `Bearer ${session.data.accessToken}`, "content-type": "application/json" }, body: JSON.stringify({ path: "../escape", data: "eA==" }) }); assert.equal(response.status, 422); assert.equal(store.webdavJobs.size, 0); } finally { await new Promise((resolve, reject) => server.close((error) => error ? reject(error) : resolve())); } }); test("access tokens reject a signed token with an unexpected JOSE header", () => { const token = issueAccessToken("user-1", "user", "header-test-secret", 900); const [, body] = token.split("."); const alteredHeader = Buffer.from(JSON.stringify({ alg: "HS512", typ: "JWT" })).toString("base64url"); const alteredBody = `${alteredHeader}.${body}`; const alteredSignature = createHmac("sha256", "header-test-secret").update(alteredBody).digest("base64url"); assert.throws(() => verifyAccessToken(`${alteredBody}.${alteredSignature}`, "header-test-secret", "user"), /登录状态已失效/); assert.doesNotThrow(() => verifyAccessToken(token, "header-test-secret", "user")); });