import { describe, expect, it } from "bun:test"; import { OAUTH_AUTHORIZATION_POPUP_PROTOCOL_VERSION, OAUTH_AUTHORIZATION_POPUP_TRANSPORT_SOURCE, oauthAuthorizationCompletionStatusAckSchema, oauthAuthorizationCompletionStatusRequestSchema, oauthAuthorizationCompletionStatusResultSchema, oauthAuthorizationHandoffFailureSchema, oauthAuthorizationPopupTransportMessageSchema, } from "./index"; const attemptId = "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8"; const request = { source: OAUTH_AUTHORIZATION_POPUP_TRANSPORT_SOURCE, protocolVersion: OAUTH_AUTHORIZATION_POPUP_PROTOCOL_VERSION, type: "oauth.authorization.completion-status.request", attemptId, } as const; const ack = { ...request, type: "oauth.authorization.completion-status.ack", } as const; const handoffFailure = { ...request, type: "oauth.authorization.handoff-failure", } as const; describe("OAuth authorization popup transport protocol", () => { it("pins the public source and protocol-version literals", () => { expect(OAUTH_AUTHORIZATION_POPUP_TRANSPORT_SOURCE).toBe( "getuserfeedback.oauth", ); expect(OAUTH_AUTHORIZATION_POPUP_PROTOCOL_VERSION).toBe(1); }); it("parses completion-status requests and acknowledgements", () => { expect( oauthAuthorizationCompletionStatusRequestSchema.parse(request), ).toEqual(request); expect(oauthAuthorizationCompletionStatusAckSchema.parse(ack)).toEqual(ack); }); it("parses only a coarse correlated handoff-failure signal", () => { expect( oauthAuthorizationHandoffFailureSchema.parse(handoffFailure), ).toEqual(handoffFailure); expect( oauthAuthorizationPopupTransportMessageSchema.parse(handoffFailure), ).toEqual(handoffFailure); for (const value of [ { ...handoffFailure, source: "getuserfeedback.preview" }, { ...handoffFailure, protocolVersion: 2 }, { ...handoffFailure, outcome: "failed" }, { ...handoffFailure, detail: "provider detail" }, ]) { expect( oauthAuthorizationHandoffFailureSchema.safeParse(value), ).toMatchObject({ success: false }); } }); it("round-trips every coarse completion outcome", () => { const outcomes = [ "connected", "reconnected", "canceled", "failed", "confirmation_required", ] as const; for (const outcome of outcomes) { const result = { ...request, type: "oauth.authorization.completion-status.result", outcome, } as const; expect( oauthAuthorizationCompletionStatusResultSchema.parse(result), ).toEqual(result); expect( oauthAuthorizationPopupTransportMessageSchema.parse(result), ).toEqual(result); } }); it("parses every message kind through the discriminated union", () => { expect( oauthAuthorizationPopupTransportMessageSchema.parse(request), ).toEqual(request); expect(oauthAuthorizationPopupTransportMessageSchema.parse(ack)).toEqual( ack, ); expect( oauthAuthorizationPopupTransportMessageSchema.parse(handoffFailure), ).toEqual(handoffFailure); }); it("rejects unknown and cross-kind fields", () => { expect( oauthAuthorizationCompletionStatusRequestSchema.safeParse({ ...request, identity: "external-account", }), ).toMatchObject({ success: false }); expect( oauthAuthorizationCompletionStatusRequestSchema.safeParse({ ...request, outcome: "connected", }), ).toMatchObject({ success: false }); expect( oauthAuthorizationCompletionStatusAckSchema.safeParse({ ...ack, outcome: "failed", }), ).toMatchObject({ success: false }); expect( oauthAuthorizationCompletionStatusResultSchema.safeParse({ ...request, type: "oauth.authorization.completion-status.result", outcome: "connected", errorDescription: "provider detail", }), ).toMatchObject({ success: false }); }); it("rejects the wrong source, protocol version, and message type", () => { const invalidRequests = [ { ...request, source: "getuserfeedback.preview" }, { ...request, protocolVersion: 2 }, { ...request, type: "oauth.authorization.completion-status.result" }, ]; for (const value of invalidRequests) { expect( oauthAuthorizationCompletionStatusRequestSchema.safeParse(value), ).toMatchObject({ success: false }); } }); it("rejects malformed and noncanonical attempt IDs", () => { const invalidAttemptIds = [ "A".repeat(42), "A".repeat(44), `${"A".repeat(42)}=`, `${"A".repeat(42)}+`, `${"A".repeat(42)}/`, `${"A".repeat(42)}B`, ]; for (const invalidAttemptId of invalidAttemptIds) { expect( oauthAuthorizationCompletionStatusRequestSchema.safeParse({ ...request, attemptId: invalidAttemptId, }), ).toMatchObject({ success: false }); } }); it("enforces the full canonical base64url alphabet for 32-byte IDs", () => { const base64urlAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; const canonicalFinalCharacters = new Set("AEIMQUYcgkosw048"); const urlSafePrefix = `${"A".repeat(40)}-_`; expect( oauthAuthorizationCompletionStatusRequestSchema.safeParse({ ...request, attemptId: `${urlSafePrefix}A`, }), ).toMatchObject({ success: true }); for (const finalCharacter of "AEIMQUYcgkosw048") { const canonicalAttemptId = `${"A".repeat(42)}${finalCharacter}`; expect(Buffer.from(canonicalAttemptId, "base64url")).toHaveLength(32); expect( oauthAuthorizationCompletionStatusRequestSchema.safeParse({ ...request, attemptId: canonicalAttemptId, }), ).toMatchObject({ success: true }); } for (const finalCharacter of base64urlAlphabet) { if (canonicalFinalCharacters.has(finalCharacter)) { continue; } expect( oauthAuthorizationCompletionStatusRequestSchema.safeParse({ ...request, attemptId: `${"A".repeat(42)}${finalCharacter}`, }), ).toMatchObject({ success: false }); } }); it("rejects unsupported or misplaced outcomes", () => { expect( oauthAuthorizationCompletionStatusResultSchema.safeParse({ ...request, type: "oauth.authorization.completion-status.result", outcome: "disconnected", }), ).toMatchObject({ success: false }); expect( oauthAuthorizationCompletionStatusResultSchema.safeParse({ ...request, type: "oauth.authorization.completion-status.result", }), ).toMatchObject({ success: false }); }); it("safe-parses untrusted browser messages without throwing", () => { const values: unknown[] = [ null, undefined, "oauth.authorization.completion-status.request", [], {}, { type: "oauth.authorization.completion-status.request" }, ]; for (const value of values) { expect(() => oauthAuthorizationPopupTransportMessageSchema.safeParse(value), ).not.toThrow(); expect( oauthAuthorizationPopupTransportMessageSchema.safeParse(value), ).toMatchObject({ success: false }); } }); });