auth-establish-refresh.test.mjs
146 lines 4.3 KB
Raw
sha256:4215cecbbabf5591b1ff69053cc938b4b6c800f0d487be40618c1d4254d8b67b security: npm audit fix pre-bridge 2026-09-05 Human 3 days ago
1 /**
2 * Behavioral tests for POST /auth/establish-refresh — browser vs CLI delivery modes.
3 */
4
5 import { test, describe } from 'node:test';
6 import assert from 'node:assert/strict';
7 import {
8 createEstablishRefreshHandler,
9 REFRESH_COOKIE_NAME,
10 } from '../hub/auth-session.mjs';
11 import { acceptIncludesRefreshTokenCli, REFRESH_TOKEN_CLI_ACCEPT } from '../hub/lib/human-session-admission.mjs';
12
13 function mockRes() {
14 /** @type {Record<string, string>} */
15 const headers = {};
16 /** @type {Record<string, string>} */
17 const cookies = {};
18 return {
19 statusCode: 200,
20 body: null,
21 set(name, value) {
22 headers[String(name).toLowerCase()] = String(value);
23 },
24 cookie(name, value) {
25 cookies[name] = value;
26 },
27 status(code) {
28 this.statusCode = code;
29 return this;
30 },
31 json(payload) {
32 this.body = payload;
33 return this;
34 },
35 headers,
36 cookies,
37 };
38 }
39
40 function sessionOk() {
41 const now = Math.floor(Date.now() / 1000);
42 return {
43 ok: true,
44 payload: {
45 sub: 'google:1',
46 type: 'session',
47 iat: now - 60,
48 exp: now - 60 + 10800,
49 },
50 };
51 }
52
53 describe('createEstablishRefreshHandler', () => {
54 const handler = createEstablishRefreshHandler({
55 store: {
56 issue: async (sub) => ({ token: `${sub}.refreshsecret` }),
57 },
58 verifyHumanSession: (token) => {
59 if (token === 'good') return sessionOk();
60 if (token === 'expired') return { ok: false, code: 'SESSION_EXPIRED' };
61 if (token === 'agent') return { ok: false, code: 'SESSION_INVALID' };
62 return { ok: false, code: 'SESSION_INVALID' };
63 },
64 cookieOptions: () => ({ httpOnly: true, secure: true, sameSite: 'none', path: '/api/v1/auth' }),
65 isBrowserOriginAllowed: (o) => o === 'https://knowtation.store',
66 acceptIncludesCliMediaType: acceptIncludesRefreshTokenCli,
67 });
68
69 test('browser Origin: cookie + established body, never refresh_token', async () => {
70 const req = {
71 headers: {
72 authorization: 'Bearer good',
73 origin: 'https://knowtation.store',
74 accept: REFRESH_TOKEN_CLI_ACCEPT,
75 },
76 };
77 const res = mockRes();
78 await handler(req, res);
79 assert.equal(res.statusCode, 200);
80 assert.equal(res.body.established, true);
81 assert.equal(res.body.refresh_token, undefined);
82 assert.equal(res.cookies[REFRESH_COOKIE_NAME], 'google:1.refreshsecret');
83 });
84
85 test('CLI no-Origin + vendor Accept: refresh_token, no cookie', async () => {
86 const req = {
87 headers: {
88 authorization: 'Bearer good',
89 accept: REFRESH_TOKEN_CLI_ACCEPT,
90 },
91 };
92 const res = mockRes();
93 await handler(req, res);
94 assert.equal(res.statusCode, 200);
95 assert.equal(res.body.refresh_token, 'google:1.refreshsecret');
96 assert.equal(res.cookies[REFRESH_COOKIE_NAME], undefined);
97 });
98
99 test('rejects missing bearer', async () => {
100 const res = mockRes();
101 await handler({ headers: {} }, res);
102 assert.equal(res.statusCode, 401);
103 assert.equal(res.body.code, 'UNAUTHORIZED');
104 });
105
106 test('rejects non-session / invalid with SESSION_INVALID', async () => {
107 const res = mockRes();
108 await handler(
109 { headers: { authorization: 'Bearer agent', origin: 'https://knowtation.store' } },
110 res,
111 );
112 assert.equal(res.statusCode, 401);
113 assert.equal(res.body.code, 'SESSION_INVALID');
114 });
115
116 test('expired session → SESSION_EXPIRED without issuing', async () => {
117 const res = mockRes();
118 await handler(
119 { headers: { authorization: 'Bearer expired', origin: 'https://knowtation.store' } },
120 res,
121 );
122 assert.equal(res.statusCode, 401);
123 assert.equal(res.body.code, 'SESSION_EXPIRED');
124 });
125
126 test('store throw → 503 SESSION_STORE_UNAVAILABLE', async () => {
127 const failing = createEstablishRefreshHandler({
128 store: {
129 issue: async () => {
130 throw new Error('blob write refused');
131 },
132 },
133 verifyHumanSession: () => sessionOk(),
134 cookieOptions: () => ({ httpOnly: true, path: '/api/v1/auth' }),
135 isBrowserOriginAllowed: () => true,
136 acceptIncludesCliMediaType: acceptIncludesRefreshTokenCli,
137 });
138 const res = mockRes();
139 await failing(
140 { headers: { authorization: 'Bearer good', origin: 'https://knowtation.store' } },
141 res,
142 );
143 assert.equal(res.statusCode, 503);
144 assert.equal(res.body.code, 'SESSION_STORE_UNAVAILABLE');
145 });
146 });
File History 1 commit
sha256:4215cecbbabf5591b1ff69053cc938b4b6c800f0d487be40618c1d4254d8b67b security: npm audit fix pre-bridge 2026-09-05 Human 3 days ago