| |
| |
| |
| |
| |
| |
| import { beforeEach, describe, expect, test } from "vitest"; |
| import { |
| signBusinessInviteToken, |
| verifyBusinessInviteToken, |
| } from "../lib/identitySigning"; |
|
|
| const TEST_SECRET = "test-business-invite-secret-minimum-32-bytes-long"; |
|
|
| describe("business invite token signing/verification", () => { |
| beforeEach(() => { |
| process.env.DODO_IDENTITY_SIGNING_SECRET = TEST_SECRET; |
| }); |
|
|
| test("round-trips a valid token", async () => { |
| const grantId = "k57c5e0m1234567890abcdef12345678"; |
| const token = await signBusinessInviteToken(grantId); |
| const ok = await verifyBusinessInviteToken(grantId, token); |
| expect(ok).toBe(true); |
| }); |
|
|
| test("rejects an expired token", async () => { |
| const grantId = "k57c5e0m1234567890abcdef12345679"; |
| const token = await signBusinessInviteToken(grantId); |
| |
| |
| const parts = token.split("."); |
| expect(parts.length).toBe(3); |
| parts[1] = String(Date.now() - 1000); |
| const expiredToken = parts.join("."); |
| const ok = await verifyBusinessInviteToken(grantId, expiredToken); |
| expect(ok).toBe(false); |
| }); |
|
|
| test("rejects a token verified against a different grantId", async () => { |
| const grantId = "k57c5e0m1234567890abcdef12345680"; |
| const token = await signBusinessInviteToken(grantId); |
| const ok = await verifyBusinessInviteToken( |
| "k57c5e0m000000000000000000000000", |
| token, |
| ); |
| expect(ok).toBe(false); |
| }); |
|
|
| test("rejects a tampered expiry timestamp", async () => { |
| const grantId = "k57c5e0m1234567890abcdef12345681"; |
| const token = await signBusinessInviteToken(grantId); |
| const parts = token.split("."); |
| expect(parts.length).toBe(3); |
| parts[1] = String(Date.now() + 86_400_000); |
| const tampered = parts.join("."); |
| const ok = await verifyBusinessInviteToken(grantId, tampered); |
| expect(ok).toBe(false); |
| }); |
|
|
| test("rejects a token with a wrong/legacy version", async () => { |
| const grantId = "k57c5e0m1234567890abcdef12345682"; |
| const token = await signBusinessInviteToken(grantId); |
| const parts = token.split("."); |
| parts[0] = "v0"; |
| const legacy = parts.join("."); |
| const ok = await verifyBusinessInviteToken(grantId, legacy); |
| expect(ok).toBe(false); |
| }); |
|
|
| test("rejects a malformed token", async () => { |
| const grantId = "k57c5e0m1234567890abcdef12345683"; |
| const ok = await verifyBusinessInviteToken(grantId, "not-a-token"); |
| expect(ok).toBe(false); |
| }); |
|
|
| test("rejects a token signed for a different purpose (domain separation)", async () => { |
| const grantId = "k57c5e0m1234567890abcdef12345684"; |
| const token = await signBusinessInviteToken(grantId); |
| |
| |
| const parts = token.split("."); |
| parts[0] = "v1-claim"; |
| const foreign = parts.join("."); |
| const ok = await verifyBusinessInviteToken(grantId, foreign); |
| expect(ok).toBe(false); |
| }); |
|
|
| test("rejects an undefined token", async () => { |
| const grantId = "k57c5e0m1234567890abcdef12345685"; |
| const ok = await verifyBusinessInviteToken(grantId, undefined); |
| expect(ok).toBe(false); |
| }); |
|
|
| test("throws when signing an empty grantId", async () => { |
| await expect(signBusinessInviteToken("")).rejects.toThrow( |
| /business invite token requires a non-empty grantId/, |
| ); |
| }); |
|
|
| test("throws when signing a grantId containing the delimiter", async () => { |
| await expect(signBusinessInviteToken("grant.with.dots")).rejects.toThrow( |
| /business invite grantId must not contain/, |
| ); |
| }); |
| }); |
|
|