diff --git a/client/src/components/AuthDebugger.tsx b/client/src/components/AuthDebugger.tsx
index c8d59c42..e7acbd80 100644
--- a/client/src/components/AuthDebugger.tsx
+++ b/client/src/components/AuthDebugger.tsx
@@ -171,7 +171,8 @@ const AuthDebugger = ({
updateAuthState({
...currentState,
isInitiatingAuth: false,
- latestError: error instanceof Error ? error : new Error(String(error)),
+ latestError:
+ error instanceof Error ? error : new Error(String(error)),
statusMessage: {
type: "error",
message: `Invalid authorization URL: ${error instanceof Error ? error.message : String(error)}`,
@@ -179,7 +180,7 @@ const AuthDebugger = ({
});
return;
}
-
+
// Store the current auth state before redirecting
sessionStorage.setItem(
SESSION_KEYS.AUTH_DEBUGGER_STATE,
diff --git a/client/src/utils/__tests__/urlValidation.test.ts b/client/src/utils/__tests__/urlValidation.test.ts
index 279197cb..9ee6a454 100644
--- a/client/src/utils/__tests__/urlValidation.test.ts
+++ b/client/src/utils/__tests__/urlValidation.test.ts
@@ -11,58 +11,64 @@ describe("validateRedirectUrl", () => {
});
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", () => {
- 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", () => {
- expect(() => validateRedirectUrl("https://example.com?param=value")).not.toThrow();
+ expect(() =>
+ validateRedirectUrl("https://example.com?param=value"),
+ ).not.toThrow();
});
});
describe("invalid URLs - XSS vectors", () => {
it("should block javascript: protocol", () => {
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", () => {
- expect(() => validateRedirectUrl("javascript:alert%28%27XSS%27%29")).toThrow(
- "Authorization URL must be HTTP or HTTPS"
- );
+ expect(() =>
+ validateRedirectUrl("javascript:alert%28%27XSS%27%29"),
+ ).toThrow("Authorization URL must be HTTP or HTTPS");
});
it("should block data: protocol", () => {
- expect(() => validateRedirectUrl("data:text/html,")).toThrow(
- "Authorization URL must be HTTP or HTTPS"
- );
+ expect(() =>
+ validateRedirectUrl("data:text/html,"),
+ ).toThrow("Authorization URL must be HTTP or HTTPS");
});
it("should block vbscript: protocol", () => {
expect(() => validateRedirectUrl("vbscript:msgbox")).toThrow(
- "Authorization URL must be HTTP or HTTPS"
+ "Authorization URL must be HTTP or HTTPS",
);
});
it("should block file: protocol", () => {
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", () => {
expect(() => validateRedirectUrl("about:blank")).toThrow(
- "Authorization URL must be HTTP or HTTPS"
+ "Authorization URL must be HTTP or HTTPS",
);
});
it("should block custom protocols", () => {
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", () => {
it("should handle malformed URLs", () => {
expect(() => validateRedirectUrl("not a url")).toThrow(
- "Invalid URL: not a url"
+ "Invalid URL: not a url",
);
});
it("should handle empty string", () => {
- expect(() => validateRedirectUrl("")).toThrow(
- "Invalid URL: "
- );
+ expect(() => validateRedirectUrl("")).toThrow("Invalid URL: ");
});
it("should handle URLs with unicode characters", () => {
@@ -91,12 +95,14 @@ describe("validateRedirectUrl", () => {
it("should handle protocol-relative URLs as invalid", () => {
expect(() => validateRedirectUrl("//example.com")).toThrow(
- "Invalid URL: //example.com"
+ "Invalid URL: //example.com",
);
});
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", () => {
- expect(() => validateRedirectUrl("java\x00script:alert('XSS')")).toThrow();
+ expect(() =>
+ validateRedirectUrl("java\x00script:alert('XSS')"),
+ ).toThrow();
});
it("should handle tab characters", () => {
@@ -120,8 +128,8 @@ describe("validateRedirectUrl", () => {
it("should handle mixed case protocols", () => {
expect(() => validateRedirectUrl("JaVaScRiPt:alert('XSS')")).toThrow(
- "Authorization URL must be HTTP or HTTPS"
+ "Authorization URL must be HTTP or HTTPS",
);
});
});
-});
\ No newline at end of file
+});
diff --git a/client/src/utils/urlValidation.ts b/client/src/utils/urlValidation.ts
index fb0ef76b..70bc458b 100644
--- a/client/src/utils/urlValidation.ts
+++ b/client/src/utils/urlValidation.ts
@@ -1,7 +1,7 @@
/**
* Validates that a URL is safe for redirection.
* Only allows HTTP and HTTPS protocols to prevent XSS attacks.
- *
+ *
* @param url - The URL string to validate
* @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");
}
} 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;
}
// If URL parsing fails, it's also invalid
throw new Error(`Invalid URL: ${url}`);
}
-}
\ No newline at end of file
+}