{
+ const tokenEndpointValidation = validateExtensionOAuthTokenEndpoint(tokenEndpoint);
+ if (!tokenEndpointValidation.ok) {
+ throw new Error(tokenEndpointValidation.reason);
+ }
+
if (state) {
await validateOAuthState(state);
}
diff --git a/apps/extension/entrypoints/content.ts b/apps/extension/entrypoints/content.ts
index e1abcc94..85abf233 100644
--- a/apps/extension/entrypoints/content.ts
+++ b/apps/extension/entrypoints/content.ts
@@ -1,7 +1,7 @@
///
import { initGoogleCalendarIntegration } from "../lib/google-calendar";
import { initLinkedInIntegration } from "../lib/linkedin";
-import { escapeHtml } from "../lib/utils";
+import { buildSafeBookingUrl, escapeHtml } from "../lib/utils";
/**
* Development-only logging utility for content scripts.
@@ -88,6 +88,10 @@ export default defineContentScript({
iframeContainer.appendChild(iframe);
+ function postToCompanionIframe(iframeWindow: Window | null, message: unknown): void {
+ iframeWindow?.postMessage(message, new URL(iframe.src).origin);
+ }
+
// Listen for messages from iframe to control width and handle OAuth
window.addEventListener("message", (event) => {
if (!iframeLoaded) return;
@@ -188,36 +192,27 @@ export default defineContentScript({
"Failed to communicate with background script:",
chrome.runtime.lastError.message
);
- iframeWindow?.postMessage(
- {
- type: "cal-extension-oauth-result",
- success: false,
- error: `Extension communication failed: ${chrome.runtime.lastError.message}`,
- },
- "*"
- );
+ postToCompanionIframe(iframeWindow, {
+ type: "cal-extension-oauth-result",
+ success: false,
+ error: `Extension communication failed: ${chrome.runtime.lastError.message}`,
+ });
return;
}
// Forward the response back to iframe
if (response.success) {
- iframeWindow?.postMessage(
- {
- type: "cal-extension-oauth-result",
- success: true,
- responseUrl: response.responseUrl,
- },
- "*"
- );
+ postToCompanionIframe(iframeWindow, {
+ type: "cal-extension-oauth-result",
+ success: true,
+ responseUrl: response.responseUrl,
+ });
} else {
- iframeWindow?.postMessage(
- {
- type: "cal-extension-oauth-result",
- success: false,
- error: response.error || "OAuth flow failed",
- },
- "*"
- );
+ postToCompanionIframe(iframeWindow, {
+ type: "cal-extension-oauth-result",
+ success: false,
+ error: response.error || "OAuth flow failed",
+ });
}
}
);
@@ -244,36 +239,27 @@ export default defineContentScript({
"Failed to communicate with background script:",
chrome.runtime.lastError.message
);
- iframeWindow?.postMessage(
- {
- type: "cal-extension-token-exchange-result",
- success: false,
- error: `Extension communication failed: ${chrome.runtime.lastError.message}`,
- },
- "*"
- );
+ postToCompanionIframe(iframeWindow, {
+ type: "cal-extension-token-exchange-result",
+ success: false,
+ error: `Extension communication failed: ${chrome.runtime.lastError.message}`,
+ });
return;
}
// Forward the response back to iframe
if (response.success) {
- iframeWindow?.postMessage(
- {
- type: "cal-extension-token-exchange-result",
- success: true,
- tokens: response.tokens,
- },
- "*"
- );
+ postToCompanionIframe(iframeWindow, {
+ type: "cal-extension-token-exchange-result",
+ success: true,
+ tokens: response.tokens,
+ });
} else {
- iframeWindow?.postMessage(
- {
- type: "cal-extension-token-exchange-result",
- success: false,
- error: response.error || "Token exchange failed",
- },
- "*"
- );
+ postToCompanionIframe(iframeWindow, {
+ type: "cal-extension-token-exchange-result",
+ success: false,
+ error: response.error || "Token exchange failed",
+ });
}
}
);
@@ -290,25 +276,19 @@ export default defineContentScript({
"Failed to communicate with background script:",
chrome.runtime.lastError.message
);
- iframeWindow?.postMessage(
- {
- type: "cal-extension-sync-tokens-result",
- success: false,
- error: `Extension communication failed: ${chrome.runtime.lastError.message}`,
- },
- "*"
- );
+ postToCompanionIframe(iframeWindow, {
+ type: "cal-extension-sync-tokens-result",
+ success: false,
+ error: `Extension communication failed: ${chrome.runtime.lastError.message}`,
+ });
return;
}
- iframeWindow?.postMessage(
- {
- type: "cal-extension-sync-tokens-result",
- success: response?.success ?? false,
- error: response?.error,
- },
- "*"
- );
+ postToCompanionIframe(iframeWindow, {
+ type: "cal-extension-sync-tokens-result",
+ success: response?.success ?? false,
+ error: response?.error,
+ });
});
}
@@ -319,25 +299,19 @@ export default defineContentScript({
"Failed to communicate with background script:",
chrome.runtime.lastError.message
);
- iframeWindow?.postMessage(
- {
- type: "cal-extension-clear-tokens-result",
- success: false,
- error: `Extension communication failed: ${chrome.runtime.lastError.message}`,
- },
- "*"
- );
+ postToCompanionIframe(iframeWindow, {
+ type: "cal-extension-clear-tokens-result",
+ success: false,
+ error: `Extension communication failed: ${chrome.runtime.lastError.message}`,
+ });
return;
}
- iframeWindow?.postMessage(
- {
- type: "cal-extension-clear-tokens-result",
- success: response?.success ?? false,
- error: response?.error,
- },
- "*"
- );
+ postToCompanionIframe(iframeWindow, {
+ type: "cal-extension-clear-tokens-result",
+ success: response?.success ?? false,
+ error: response?.error,
+ });
});
}
@@ -453,7 +427,7 @@ export default defineContentScript({
// Send message to iframe to reload cache
if (iframe.contentWindow) {
- iframe.contentWindow.postMessage({ type: "cal-companion-reload-cache" }, "*");
+ postToCompanionIframe(iframe.contentWindow, { type: "cal-companion-reload-cache" });
}
});
@@ -1089,11 +1063,7 @@ export default defineContentScript({
previewBtn.addEventListener("click", (e) => {
e.stopPropagation();
- const bookingUrl =
- eventType.bookingUrl ||
- `https://cal.com/${
- eventType.users?.[0]?.username || "user"
- }/${eventType.slug}`;
+ const bookingUrl = buildSafeBookingUrl(eventType);
window.open(bookingUrl, "_blank");
});
previewBtn.addEventListener("mouseenter", () => {
@@ -1133,11 +1103,7 @@ export default defineContentScript({
copyBtn.addEventListener("click", (e) => {
e.stopPropagation();
// Copy to clipboard
- const bookingUrl =
- eventType.bookingUrl ||
- `https://cal.com/${
- eventType.users?.[0]?.username || "user"
- }/${eventType.slug}`;
+ const bookingUrl = buildSafeBookingUrl(eventType);
navigator.clipboard
.writeText(bookingUrl)
.then(() => {
@@ -1265,7 +1231,7 @@ export default defineContentScript({
Something went wrong
- ${errorMessage || "Failed to load event types"}
+ ${escapeHtml(errorMessage || "Failed to load event types")}