42 lines
1.4 KiB
TypeScript
42 lines
1.4 KiB
TypeScript
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|||
|
|
import {
|
||
|
|
base64UrlEncode,
|
||
|
|
computeCodeChallenge,
|
||
|
|
generateCodeVerifier,
|
||
|
|
generateState,
|
||
|
|
isLikelyValidVerifier,
|
||
|
|
} from "./pkce";
|
||
|
|
|
||
|
|
describe("PKCE helpers", () => {
|
||
|
|
it("base64UrlEncode has no padding and url-safe characters", () => {
|
||
|
|
// bytes chosen to force "+" and "/" and padding in plain base64
|
||
|
|
const bytes = new Uint8Array([0xfb, 0xff, 0xbf, 0xff]);
|
||
|
|
const encoded = base64UrlEncode(bytes);
|
||
|
|
expect(encoded).not.toMatch(/[+/=]/);
|
||
|
|
});
|
||
|
|
|
||
|
|
it("computes the RFC 7636 appendix-B S256 vector", async () => {
|
||
|
|
const verifier =
|
||
|
|
"dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk";
|
||
|
|
const challenge = await computeCodeChallenge(verifier);
|
||
|
|
expect(challenge).toBe("E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM");
|
||
|
|
});
|
||
|
|
|
||
|
|
it("generates verifiers with valid charset and length", () => {
|
||
|
|
for (let i = 0; i < 20; i++) {
|
||
|
|
const verifier = generateCodeVerifier();
|
||
|
|
expect(isLikelyValidVerifier(verifier)).toBe(true);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
it("rejects verifiers outside 43-128 chars or with reserved chars", () => {
|
||
|
|
expect(isLikelyValidVerifier("short")).toBe(false);
|
||
|
|
expect(isLikelyValidVerifier("a".repeat(129))).toBe(false);
|
||
|
|
expect(isLikelyValidVerifier("a".repeat(43) + "+")).toBe(false);
|
||
|
|
});
|
||
|
|
|
||
|
|
it("generates distinct random states", () => {
|
||
|
|
expect(generateState()).not.toBe(generateState());
|
||
|
|
});
|
||
|
|
});
|