import assert from "node:assert/strict"; import test from "node:test"; import { getWecomOAuthSecret, resolveWecomClaimant, signWecomIdentityTicket, verifyWecomIdentityTicket, wecomClaimantPartnerId, WECOM_IDENTITY_TTL_MS, } from "../lib/wecom-oauth-service.ts"; const SECRET = "internal-token-test"; function fakePartnerDb(partners = []) { return { prepare(sql) { return { bind(...params) { return { async first() { if (/WHERE wecom_external_user_id = \?/.test(sql)) { const row = partners.find( (item) => item.wecom_external_user_id === params[0], ); return row ? { id: row.id } : null; } return null; }, }; }, }; }, }; } test("identity ticket sign → verify roundtrip", async () => { const { ticket } = await signWecomIdentityTicket("wmExt123", "张三", { secret: SECRET, }); const identity = await verifyWecomIdentityTicket(ticket, { secret: SECRET }); assert.deepEqual(identity, { externalUserId: "wmExt123", displayName: "张三" }); }); test("identity ticket falls back to default display name when empty", async () => { const { ticket } = await signWecomIdentityTicket("wmExt123", " ", { secret: SECRET, }); const identity = await verifyWecomIdentityTicket(ticket, { secret: SECRET }); assert.equal(identity.displayName, "企微客户"); }); test("identity ticket default TTL is 30 minutes and expiresIn matches", async () => { const now = Date.now(); const { ticket, expiresIn } = await signWecomIdentityTicket("wmExt123", "张三", { secret: SECRET, nowMs: now, }); assert.equal(expiresIn, 30 * 60); const identity = await verifyWecomIdentityTicket(ticket, { secret: SECRET, nowMs: now + WECOM_IDENTITY_TTL_MS - 1, }); assert.ok(identity, "still valid just before expiry"); const expired = await verifyWecomIdentityTicket(ticket, { secret: SECRET, nowMs: now + WECOM_IDENTITY_TTL_MS + 61_000, }); assert.equal(expired, null, "expired beyond grace window"); }); test("identity ticket passes within 60s grace window", async () => { const now = Date.now(); const { ticket } = await signWecomIdentityTicket("wmExt123", "张三", { secret: SECRET, nowMs: now, }); const identity = await verifyWecomIdentityTicket(ticket, { secret: SECRET, nowMs: now + WECOM_IDENTITY_TTL_MS + 30_000, }); assert.deepEqual(identity?.externalUserId, "wmExt123"); }); test("identity ticket verification fails on wrong secret", async () => { const { ticket } = await signWecomIdentityTicket("wmExt123", "张三", { secret: SECRET, }); assert.equal( await verifyWecomIdentityTicket(ticket, { secret: "other-secret" }), null, ); }); test("identity ticket verification fails on tampered payload", async () => { const { ticket } = await signWecomIdentityTicket("wmExt123", "张三", { secret: SECRET, }); const [payload, signature] = ticket.split("."); const decoded = JSON.parse( Buffer.from(payload.replace(/-/g, "+").replace(/_/g, "/"), "base64").toString( "utf8", ), ); decoded.ext = "wmVictim"; const forgedPayload = Buffer.from(JSON.stringify(decoded)) .toString("base64") .replace(/\+/g, "-") .replace(/\//g, "_") .replace(/=+$/, ""); assert.equal( await verifyWecomIdentityTicket(`${forgedPayload}.${signature}`, { secret: SECRET, }), null, ); }); test("identity ticket verification fails on malformed input", async () => { for (const bad of ["", "no-dot", ".abc", "abc.", "a b.c d", "xxx.yyy"]) { assert.equal( await verifyWecomIdentityTicket(bad, { secret: SECRET }), null, `rejects ${JSON.stringify(bad)}`, ); } }); test("getWecomOAuthSecret throws when ADMIN_INTERNAL_TOKEN missing", () => { const previous = process.env.ADMIN_INTERNAL_TOKEN; delete process.env.ADMIN_INTERNAL_TOKEN; try { assert.throws(() => getWecomOAuthSecret(), /ADMIN_INTERNAL_TOKEN/); } finally { if (previous !== undefined) process.env.ADMIN_INTERNAL_TOKEN = previous; } }); test("wecomClaimantPartnerId derives stable partner-ext id", () => { const first = wecomClaimantPartnerId("wmExt123"); assert.match(first, /^partner-ext-[a-z0-9]+$/); assert.equal(first, wecomClaimantPartnerId("wmExt123")); assert.notEqual(first, wecomClaimantPartnerId("wmExt456")); }); test("resolveWecomClaimant reuses partner bound by operator", async () => { const db = fakePartnerDb([ { id: "partner-9", wecom_external_user_id: "wmExt123" }, ]); const resolved = await resolveWecomClaimant(db, "wmExt123"); assert.deepEqual(resolved, { partnerId: "partner-9", matchedExisting: true }); }); test("resolveWecomClaimant derives new id when unbound", async () => { const db = fakePartnerDb(); const resolved = await resolveWecomClaimant(db, "wmExt123"); assert.equal(resolved.matchedExisting, false); assert.equal(resolved.partnerId, wecomClaimantPartnerId("wmExt123")); });