Apply Prettier formatting

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Jenn Newton 2025-08-21 15:41:33 +00:00
commit a018a6d758
No known key found for this signature in database
3 changed files with 40 additions and 28 deletions

View file

@ -171,7 +171,8 @@ const AuthDebugger = ({
updateAuthState({ updateAuthState({
...currentState, ...currentState,
isInitiatingAuth: false, isInitiatingAuth: false,
latestError: error instanceof Error ? error : new Error(String(error)), latestError:
error instanceof Error ? error : new Error(String(error)),
statusMessage: { statusMessage: {
type: "error", type: "error",
message: `Invalid authorization URL: ${error instanceof Error ? error.message : String(error)}`, message: `Invalid authorization URL: ${error instanceof Error ? error.message : String(error)}`,
@ -179,7 +180,7 @@ const AuthDebugger = ({
}); });
return; return;
} }
// Store the current auth state before redirecting // Store the current auth state before redirecting
sessionStorage.setItem( sessionStorage.setItem(
SESSION_KEYS.AUTH_DEBUGGER_STATE, SESSION_KEYS.AUTH_DEBUGGER_STATE,

View file

@ -11,58 +11,64 @@ describe("validateRedirectUrl", () => {
}); });
it("should allow URLs with ports", () => { it("should allow URLs with ports", () => {
expect(() => validateRedirectUrl("https://example.com:8080")).not.toThrow(); expect(() =>
validateRedirectUrl("https://example.com:8080"),
).not.toThrow();
}); });
it("should allow URLs with paths", () => { it("should allow URLs with paths", () => {
expect(() => validateRedirectUrl("https://example.com/path/to/auth")).not.toThrow(); expect(() =>
validateRedirectUrl("https://example.com/path/to/auth"),
).not.toThrow();
}); });
it("should allow URLs with query parameters", () => { it("should allow URLs with query parameters", () => {
expect(() => validateRedirectUrl("https://example.com?param=value")).not.toThrow(); expect(() =>
validateRedirectUrl("https://example.com?param=value"),
).not.toThrow();
}); });
}); });
describe("invalid URLs - XSS vectors", () => { describe("invalid URLs - XSS vectors", () => {
it("should block javascript: protocol", () => { it("should block javascript: protocol", () => {
expect(() => validateRedirectUrl("javascript:alert('XSS')")).toThrow( expect(() => validateRedirectUrl("javascript:alert('XSS')")).toThrow(
"Authorization URL must be HTTP or HTTPS" "Authorization URL must be HTTP or HTTPS",
); );
}); });
it("should block javascript: with encoded characters", () => { it("should block javascript: with encoded characters", () => {
expect(() => validateRedirectUrl("javascript:alert%28%27XSS%27%29")).toThrow( expect(() =>
"Authorization URL must be HTTP or HTTPS" validateRedirectUrl("javascript:alert%28%27XSS%27%29"),
); ).toThrow("Authorization URL must be HTTP or HTTPS");
}); });
it("should block data: protocol", () => { it("should block data: protocol", () => {
expect(() => validateRedirectUrl("data:text/html,<script>alert('XSS')</script>")).toThrow( expect(() =>
"Authorization URL must be HTTP or HTTPS" validateRedirectUrl("data:text/html,<script>alert('XSS')</script>"),
); ).toThrow("Authorization URL must be HTTP or HTTPS");
}); });
it("should block vbscript: protocol", () => { it("should block vbscript: protocol", () => {
expect(() => validateRedirectUrl("vbscript:msgbox")).toThrow( expect(() => validateRedirectUrl("vbscript:msgbox")).toThrow(
"Authorization URL must be HTTP or HTTPS" "Authorization URL must be HTTP or HTTPS",
); );
}); });
it("should block file: protocol", () => { it("should block file: protocol", () => {
expect(() => validateRedirectUrl("file:///etc/passwd")).toThrow( expect(() => validateRedirectUrl("file:///etc/passwd")).toThrow(
"Authorization URL must be HTTP or HTTPS" "Authorization URL must be HTTP or HTTPS",
); );
}); });
it("should block about: protocol", () => { it("should block about: protocol", () => {
expect(() => validateRedirectUrl("about:blank")).toThrow( expect(() => validateRedirectUrl("about:blank")).toThrow(
"Authorization URL must be HTTP or HTTPS" "Authorization URL must be HTTP or HTTPS",
); );
}); });
it("should block custom protocols", () => { it("should block custom protocols", () => {
expect(() => validateRedirectUrl("custom://example")).toThrow( expect(() => validateRedirectUrl("custom://example")).toThrow(
"Authorization URL must be HTTP or HTTPS" "Authorization URL must be HTTP or HTTPS",
); );
}); });
}); });
@ -70,14 +76,12 @@ describe("validateRedirectUrl", () => {
describe("edge cases", () => { describe("edge cases", () => {
it("should handle malformed URLs", () => { it("should handle malformed URLs", () => {
expect(() => validateRedirectUrl("not a url")).toThrow( expect(() => validateRedirectUrl("not a url")).toThrow(
"Invalid URL: not a url" "Invalid URL: not a url",
); );
}); });
it("should handle empty string", () => { it("should handle empty string", () => {
expect(() => validateRedirectUrl("")).toThrow( expect(() => validateRedirectUrl("")).toThrow("Invalid URL: ");
"Invalid URL: "
);
}); });
it("should handle URLs with unicode characters", () => { it("should handle URLs with unicode characters", () => {
@ -91,12 +95,14 @@ describe("validateRedirectUrl", () => {
it("should handle protocol-relative URLs as invalid", () => { it("should handle protocol-relative URLs as invalid", () => {
expect(() => validateRedirectUrl("//example.com")).toThrow( expect(() => validateRedirectUrl("//example.com")).toThrow(
"Invalid URL: //example.com" "Invalid URL: //example.com",
); );
}); });
it("should handle URLs with authentication", () => { it("should handle URLs with authentication", () => {
expect(() => validateRedirectUrl("https://user:pass@example.com")).not.toThrow(); expect(() =>
validateRedirectUrl("https://user:pass@example.com"),
).not.toThrow();
}); });
}); });
@ -107,7 +113,9 @@ describe("validateRedirectUrl", () => {
}); });
it("should handle null bytes", () => { it("should handle null bytes", () => {
expect(() => validateRedirectUrl("java\x00script:alert('XSS')")).toThrow(); expect(() =>
validateRedirectUrl("java\x00script:alert('XSS')"),
).toThrow();
}); });
it("should handle tab characters", () => { it("should handle tab characters", () => {
@ -120,8 +128,8 @@ describe("validateRedirectUrl", () => {
it("should handle mixed case protocols", () => { it("should handle mixed case protocols", () => {
expect(() => validateRedirectUrl("JaVaScRiPt:alert('XSS')")).toThrow( expect(() => validateRedirectUrl("JaVaScRiPt:alert('XSS')")).toThrow(
"Authorization URL must be HTTP or HTTPS" "Authorization URL must be HTTP or HTTPS",
); );
}); });
}); });
}); });

View file

@ -1,7 +1,7 @@
/** /**
* Validates that a URL is safe for redirection. * Validates that a URL is safe for redirection.
* Only allows HTTP and HTTPS protocols to prevent XSS attacks. * Only allows HTTP and HTTPS protocols to prevent XSS attacks.
* *
* @param url - The URL string to validate * @param url - The URL string to validate
* @throws Error if the URL has an unsafe protocol * @throws Error if the URL has an unsafe protocol
*/ */
@ -12,10 +12,13 @@ export function validateRedirectUrl(url: string): void {
throw new Error("Authorization URL must be HTTP or HTTPS"); throw new Error("Authorization URL must be HTTP or HTTPS");
} }
} catch (error) { } catch (error) {
if (error instanceof Error && error.message === "Authorization URL must be HTTP or HTTPS") { if (
error instanceof Error &&
error.message === "Authorization URL must be HTTP or HTTPS"
) {
throw error; throw error;
} }
// If URL parsing fails, it's also invalid // If URL parsing fails, it's also invalid
throw new Error(`Invalid URL: ${url}`); throw new Error(`Invalid URL: ${url}`);
} }
} }