|
1 | 1 | import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; |
2 | | -import { authenticateToPlatform, parseAuthUri } from "../auth"; |
3 | | -import { TestCryptoAdapter } from "./TestCryptoAdapter"; |
4 | | - |
5 | | -describe("parseAuthUri", () => { |
6 | | - it("parses w3ds://auth URI", () => { |
7 | | - const uri = |
8 | | - "w3ds://auth?redirect=https%3A%2F%2Fplatform.test%2Fapi%2Fauth&session=sess-123&platform=myapp"; |
9 | | - const parsed = parseAuthUri(uri); |
10 | | - expect(parsed.redirectUrl).toBe("https://platform.test/api/auth"); |
11 | | - expect(parsed.sessionId).toBe("sess-123"); |
12 | | - expect(parsed.platform).toBe("myapp"); |
13 | | - }); |
14 | | - |
15 | | - it("throws on invalid URL", () => { |
16 | | - expect(() => parseAuthUri("not-a-url")).toThrow("Invalid auth URI"); |
17 | | - }); |
18 | | - |
19 | | - it("throws on wrong scheme", () => { |
20 | | - expect(() => parseAuthUri("https://auth?redirect=x&session=y")).toThrow( |
21 | | - "expected scheme w3ds://auth" |
22 | | - ); |
23 | | - }); |
24 | | - |
25 | | - it("throws when redirect missing", () => { |
26 | | - expect(() => |
27 | | - parseAuthUri("w3ds://auth?session=s1&platform=p") |
28 | | - ).toThrow("missing redirect"); |
29 | | - }); |
30 | | - |
31 | | - it("throws when session missing", () => { |
32 | | - expect(() => |
33 | | - parseAuthUri("w3ds://auth?redirect=https%3A%2F%2Fa.b%2Fc&platform=p") |
34 | | - ).toThrow("missing session"); |
35 | | - }); |
36 | | -}); |
37 | | - |
38 | | -describe("authenticateToPlatform", () => { |
39 | | - const adapter = new TestCryptoAdapter(); |
40 | | - |
41 | | - beforeEach(async () => { |
42 | | - await adapter.generateKeyPair(); |
43 | | - }); |
44 | | - |
45 | | - afterEach(() => { |
46 | | - vi.unstubAllGlobals(); |
47 | | - }); |
48 | | - |
49 | | - it("POSTs ename, session, signature to redirect URL", async () => { |
50 | | - const authUri = |
51 | | - "w3ds://auth?redirect=https%3A%2F%2Fplatform.test%2Fapi%2Fauth&session=sess-456&platform=test"; |
52 | | - let capturedBody: Record<string, string> = {}; |
53 | | - vi.stubGlobal( |
54 | | - "fetch", |
55 | | - vi.fn((input: string | URL, init?: RequestInit) => { |
56 | | - const url = typeof input === "string" ? input : input.toString(); |
57 | | - if (url === "https://platform.test/api/auth") { |
58 | | - capturedBody = init?.body ? JSON.parse(init.body as string) : {}; |
59 | | - return Promise.resolve( |
60 | | - new Response(JSON.stringify({ token: "jwt-123" }), { status: 200 }) |
61 | | - ); |
62 | | - } |
63 | | - return Promise.reject(new Error(`Unexpected: ${url}`)); |
64 | | - }) |
65 | | - ); |
66 | | - |
67 | | - const result = await authenticateToPlatform({ |
68 | | - cryptoAdapter: adapter, |
69 | | - keyId: "test-key-1", |
70 | | - w3id: "w3id-xyz", |
71 | | - authUri, |
72 | | - }); |
73 | | - |
74 | | - expect(result.success).toBe(true); |
75 | | - expect(result.token).toBe("jwt-123"); |
76 | | - expect(capturedBody.ename).toBe("w3id-xyz"); |
77 | | - expect(capturedBody.session).toBe("sess-456"); |
78 | | - expect(capturedBody.signature).toMatch(/^sig:test-key-1:/); |
79 | | - }); |
80 | | - |
81 | | - it("includes appVersion when provided", async () => { |
82 | | - const authUri = |
83 | | - "w3ds://auth?redirect=https%3A%2F%2Fp.test%2Fauth&session=s1&platform=p"; |
84 | | - let capturedBody: Record<string, string> = {}; |
85 | | - vi.stubGlobal( |
86 | | - "fetch", |
87 | | - vi.fn((_input: string | URL, init?: RequestInit) => { |
88 | | - capturedBody = init?.body ? JSON.parse(init.body as string) : {}; |
89 | | - return Promise.resolve( |
90 | | - new Response(JSON.stringify({}), { status: 200 }) |
91 | | - ); |
92 | | - }) |
93 | | - ); |
94 | | - |
95 | | - await authenticateToPlatform({ |
96 | | - cryptoAdapter: adapter, |
97 | | - keyId: "test-key-1", |
98 | | - w3id: "w3id", |
99 | | - authUri, |
100 | | - appVersion: "1.0.0", |
101 | | - }); |
102 | | - |
103 | | - expect(capturedBody.appVersion).toBe("1.0.0"); |
104 | | - }); |
105 | | - |
106 | | - it("throws when platform returns error", async () => { |
107 | | - const authUri = |
108 | | - "w3ds://auth?redirect=https%3A%2F%2Fp.test%2Fauth&session=s1&platform=p"; |
109 | | - vi.stubGlobal( |
110 | | - "fetch", |
111 | | - vi.fn(() => |
112 | | - Promise.resolve( |
113 | | - new Response( |
114 | | - JSON.stringify({ error: "Invalid session" }), |
115 | | - { status: 400 } |
116 | | - ) |
117 | | - ) |
118 | | - ) |
119 | | - ); |
120 | | - |
121 | | - await expect( |
122 | | - authenticateToPlatform({ |
123 | | - cryptoAdapter: adapter, |
124 | | - keyId: "test-key-1", |
125 | | - w3id: "w3id", |
126 | | - authUri, |
127 | | - }) |
128 | | - ).rejects.toThrow(/Platform auth failed/); |
129 | | - }); |
| 2 | +import { authenticate } from "../auth.js"; |
| 3 | +import { TestCryptoAdapter } from "./TestCryptoAdapter.js"; |
| 4 | + |
| 5 | +describe("authenticate", () => { |
| 6 | + const adapter = new TestCryptoAdapter(); |
| 7 | + const CONTEXT = "onboarding"; |
| 8 | + |
| 9 | + beforeEach(async () => { |
| 10 | + await adapter.ensureKey("default", CONTEXT); |
| 11 | + }); |
| 12 | + |
| 13 | + afterEach(() => { |
| 14 | + vi.unstubAllGlobals(); |
| 15 | + }); |
| 16 | + |
| 17 | + it("returns signature from adapter", async () => { |
| 18 | + const result = await authenticate(adapter, { |
| 19 | + sessionId: "sess-123", |
| 20 | + keyId: "default", |
| 21 | + context: CONTEXT, |
| 22 | + }); |
| 23 | + expect(result.signature).toMatch(/^sig:default:/); |
| 24 | + const b64 = result.signature.replace(/^sig:default:/, ""); |
| 25 | + expect(atob(b64)).toBe("sess-123"); |
| 26 | + }); |
| 27 | + |
| 28 | + it("uses custom keyId when provided", async () => { |
| 29 | + await adapter.ensureKey("test-key-1", CONTEXT); |
| 30 | + const result = await authenticate(adapter, { |
| 31 | + sessionId: "hello", |
| 32 | + keyId: "test-key-1", |
| 33 | + context: CONTEXT, |
| 34 | + }); |
| 35 | + expect(result.signature).toMatch(/^sig:test-key-1:/); |
| 36 | + }); |
130 | 37 | }); |
0 commit comments