@ex-machina/opencode-anthropic-auth 1.1.2 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/constants.d.ts +3 -0
- package/dist/constants.js +7 -0
- package/dist/index.js +2 -10
- package/dist/tests/auth.test.d.ts +1 -0
- package/dist/tests/auth.test.js +87 -0
- package/dist/tests/index.test.d.ts +1 -0
- package/dist/tests/index.test.js +481 -0
- package/dist/tests/pkce.test.d.ts +1 -0
- package/dist/tests/pkce.test.js +111 -0
- package/dist/tests/transform.test.d.ts +1 -0
- package/dist/tests/transform.test.js +621 -0
- package/dist/transform.d.ts +22 -0
- package/dist/transform.js +112 -1
- package/package.json +1 -1
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { afterEach, describe, expect, mock, test } from 'bun:test';
|
|
2
|
+
import { generatePKCE } from '../pkce';
|
|
3
|
+
afterEach(() => {
|
|
4
|
+
mock.restore();
|
|
5
|
+
});
|
|
6
|
+
describe('generatePKCE', () => {
|
|
7
|
+
test('returns an object with verifier, challenge, and method', async () => {
|
|
8
|
+
const result = await generatePKCE();
|
|
9
|
+
expect(result).toHaveProperty('verifier');
|
|
10
|
+
expect(result).toHaveProperty('challenge');
|
|
11
|
+
expect(result).toHaveProperty('method');
|
|
12
|
+
});
|
|
13
|
+
test('method is S256', async () => {
|
|
14
|
+
const result = await generatePKCE();
|
|
15
|
+
expect(result.method).toBe('S256');
|
|
16
|
+
});
|
|
17
|
+
test('verifier is 86 characters (64 bytes base64url)', async () => {
|
|
18
|
+
const result = await generatePKCE();
|
|
19
|
+
expect(result.verifier.length).toBe(86);
|
|
20
|
+
});
|
|
21
|
+
test('challenge is 43 characters (SHA-256 base64url)', async () => {
|
|
22
|
+
const result = await generatePKCE();
|
|
23
|
+
expect(result.challenge.length).toBe(43);
|
|
24
|
+
});
|
|
25
|
+
test('verifier contains only base64url characters', async () => {
|
|
26
|
+
const result = await generatePKCE();
|
|
27
|
+
expect(result.verifier).toMatch(/^[A-Za-z0-9_-]+$/);
|
|
28
|
+
});
|
|
29
|
+
test('challenge contains only base64url characters', async () => {
|
|
30
|
+
const result = await generatePKCE();
|
|
31
|
+
expect(result.challenge).toMatch(/^[A-Za-z0-9_-]+$/);
|
|
32
|
+
});
|
|
33
|
+
test('verifier has no base64 padding or unsafe chars', async () => {
|
|
34
|
+
const result = await generatePKCE();
|
|
35
|
+
expect(result.verifier).not.toContain('+');
|
|
36
|
+
expect(result.verifier).not.toContain('/');
|
|
37
|
+
expect(result.verifier).not.toContain('=');
|
|
38
|
+
});
|
|
39
|
+
test('challenge has no base64 padding or unsafe chars', async () => {
|
|
40
|
+
const result = await generatePKCE();
|
|
41
|
+
expect(result.challenge).not.toContain('+');
|
|
42
|
+
expect(result.challenge).not.toContain('/');
|
|
43
|
+
expect(result.challenge).not.toContain('=');
|
|
44
|
+
});
|
|
45
|
+
test('challenge is SHA-256 of verifier (independent verification)', async () => {
|
|
46
|
+
const result = await generatePKCE();
|
|
47
|
+
const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(result.verifier));
|
|
48
|
+
const hashBytes = new Uint8Array(digest);
|
|
49
|
+
let bin = '';
|
|
50
|
+
for (const byte of hashBytes)
|
|
51
|
+
bin += String.fromCharCode(byte);
|
|
52
|
+
const expected = btoa(bin)
|
|
53
|
+
.replace(/\+/g, '-')
|
|
54
|
+
.replace(/\//g, '_')
|
|
55
|
+
.replace(/=/g, '');
|
|
56
|
+
expect(result.challenge).toBe(expected);
|
|
57
|
+
});
|
|
58
|
+
test('consecutive calls produce different verifiers', async () => {
|
|
59
|
+
const a = await generatePKCE();
|
|
60
|
+
const b = await generatePKCE();
|
|
61
|
+
expect(a.verifier).not.toBe(b.verifier);
|
|
62
|
+
});
|
|
63
|
+
test('consecutive calls produce different challenges', async () => {
|
|
64
|
+
const a = await generatePKCE();
|
|
65
|
+
const b = await generatePKCE();
|
|
66
|
+
expect(a.challenge).not.toBe(b.challenge);
|
|
67
|
+
});
|
|
68
|
+
test('verifier is within RFC 7636 bounds (43-128 chars)', async () => {
|
|
69
|
+
const result = await generatePKCE();
|
|
70
|
+
expect(result.verifier.length).toBeGreaterThanOrEqual(43);
|
|
71
|
+
expect(result.verifier.length).toBeLessThanOrEqual(128);
|
|
72
|
+
});
|
|
73
|
+
test('deterministic output for known random bytes', async () => {
|
|
74
|
+
// Bytes 0-63 produce +, / and = in raw base64,
|
|
75
|
+
// pinning all three .replace() calls
|
|
76
|
+
const knownBytes = new Uint8Array(64);
|
|
77
|
+
for (let i = 0; i < 64; i++)
|
|
78
|
+
knownBytes[i] = i;
|
|
79
|
+
const original = crypto.getRandomValues;
|
|
80
|
+
crypto.getRandomValues = ((array) => {
|
|
81
|
+
new Uint8Array(array.buffer, array.byteOffset, array.byteLength).set(knownBytes);
|
|
82
|
+
return array;
|
|
83
|
+
});
|
|
84
|
+
try {
|
|
85
|
+
const result = await generatePKCE();
|
|
86
|
+
// Expected verifier: base64url(bytes 0..63)
|
|
87
|
+
let bin = '';
|
|
88
|
+
for (let i = 0; i < 64; i++)
|
|
89
|
+
bin += String.fromCharCode(i);
|
|
90
|
+
const expectedVerifier = btoa(bin)
|
|
91
|
+
.replace(/\+/g, '-')
|
|
92
|
+
.replace(/\//g, '_')
|
|
93
|
+
.replace(/=/g, '');
|
|
94
|
+
expect(result.verifier).toBe(expectedVerifier);
|
|
95
|
+
// Expected challenge: base64url(SHA-256(verifier))
|
|
96
|
+
const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(expectedVerifier));
|
|
97
|
+
const hashBytes = new Uint8Array(digest);
|
|
98
|
+
let hashBin = '';
|
|
99
|
+
for (const byte of hashBytes)
|
|
100
|
+
hashBin += String.fromCharCode(byte);
|
|
101
|
+
const expectedChallenge = btoa(hashBin)
|
|
102
|
+
.replace(/\+/g, '-')
|
|
103
|
+
.replace(/\//g, '_')
|
|
104
|
+
.replace(/=/g, '');
|
|
105
|
+
expect(result.challenge).toBe(expectedChallenge);
|
|
106
|
+
}
|
|
107
|
+
finally {
|
|
108
|
+
crypto.getRandomValues = original;
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|