companion-oauth-pkce-stress.test.mjs
85 lines 2.9 KB
Raw
sha256:8915fe406161f95c1681f9469375e7bae5b28c884f00bedbdef65e4b0cd0738d docs(flow): commit FLOW-V0-SPEC.md hygiene for 7A-INT merge Human 19 hours ago
1 /**
2 * Tier 4 — STRESS: high-volume generation and validation. Asserts no collisions in CSPRNG output,
3 * no accidental "ok" under a flood of hostile inputs, and bounded behavior at scale.
4 */
5 import { describe, it } from 'node:test';
6 import assert from 'node:assert/strict';
7 import crypto from 'node:crypto';
8 import {
9 createPkcePair,
10 createOAuthState,
11 createNonce,
12 computeCodeChallenge,
13 validateAuthorizationResponse,
14 validateTokenResponse,
15 validateRedirectUri,
16 } from '../lib/companion-oauth-pkce.mjs';
17
18 describe('Stress — CSPRNG outputs are unique and correct at volume', () => {
19 it('50k PKCE pairs: all verifiers unique, all challenges correct', () => {
20 const N = 50_000;
21 const verifiers = new Set();
22 for (let i = 0; i < N; i++) {
23 const { codeVerifier, codeChallenge } = createPkcePair();
24 verifiers.add(codeVerifier);
25 if (i % 5000 === 0) {
26 assert.equal(codeChallenge, crypto.createHash('sha256').update(codeVerifier, 'ascii').digest('base64url'));
27 }
28 }
29 assert.equal(verifiers.size, N, 'no verifier collisions');
30 });
31
32 it('100k states + nonces: no collisions', () => {
33 const N = 100_000;
34 const states = new Set();
35 const nonces = new Set();
36 for (let i = 0; i < N; i++) {
37 states.add(createOAuthState());
38 nonces.add(createNonce());
39 }
40 assert.equal(states.size, N);
41 assert.equal(nonces.size, N);
42 });
43 });
44
45 describe('Stress — 100k wrong-state callbacks never admit', () => {
46 it('an exhaustive flood of mismatched states is always rejected', () => {
47 const expected = createOAuthState();
48 let admits = 0;
49 for (let i = 0; i < 100_000; i++) {
50 const r = validateAuthorizationResponse({ params: { code: 'c', state: 'guess-' + i }, expectedState: expected });
51 if (r.ok) admits += 1;
52 }
53 assert.equal(admits, 0);
54 });
55 });
56
57 describe('Stress — hostile token responses never validate', () => {
58 it('50k malformed token responses all fail closed', () => {
59 let oks = 0;
60 for (let i = 0; i < 50_000; i++) {
61 const variants = [
62 { access_token: '', token_type: 'Bearer', expires_in: 60 },
63 { access_token: 'x'.repeat((i % 20000) + 1), token_type: 'Bearer' }, // no expires_in
64 { access_token: 'x', token_type: 'nope', expires_in: 60 },
65 { error: 'e' + i },
66 ];
67 const v = validateTokenResponse(variants[i % variants.length]);
68 if (v.ok) oks += 1;
69 }
70 assert.equal(oks, 0);
71 });
72 });
73
74 describe('Stress — large redirect inputs are bounded and rejected', () => {
75 it('an oversized redirect uri is rejected without error', () => {
76 const huge = 'http://127.0.0.1:49321/' + 'a'.repeat(20000);
77 const r = validateRedirectUri(huge);
78 assert.equal(r.ok, false);
79 });
80 it('many computeCodeChallenge calls stay correct', () => {
81 const v = createPkcePair().codeVerifier;
82 const expected = computeCodeChallenge(v);
83 for (let i = 0; i < 20_000; i++) assert.equal(computeCodeChallenge(v), expected);
84 });
85 });
File History 1 commit
sha256:8915fe406161f95c1681f9469375e7bae5b28c884f00bedbdef65e4b0cd0738d docs(flow): commit FLOW-V0-SPEC.md hygiene for 7A-INT merge Human 19 hours ago