Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions emain/emain-tabview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -319,9 +319,26 @@ export async function getOrCreateWebViewForTab(waveWindowId: string, tabId: stri
if (wc == null || wc.isDestroyed() || tabView.webContents == null || tabView.webContents.isDestroyed()) {
return { action: "deny" };
}
// OAuth/SSO flows call window.open(url, name, "width=...,height=...") which Electron
// reports as disposition "new-window". They require a real popup that preserves the
// window.opener relationship (postMessage token return) and a valid Cross-Origin-
// Opener-Policy browsing context. Rerouting them into a new web block breaks both
// (results in ERR_BLOCKED_BY_RESPONSE). Allow a genuine popup window for these; it
// shares wc's session so any auth cookies/tokens remain visible to the webview.
// Gate on a non-empty features string: a shift+click on a plain link also reports
// disposition "new-window" but carries no features, and must keep routing to a web block.
if (details.disposition === "new-window" && details.features !== "") {
return {
action: "allow",
overrideBrowserWindowOptions: { width: 600, height: 700, autoHideMenuBar: true },
};
}
// Plain link clicks (target=_blank, foreground/background tab) keep existing behavior:
// open in a new Wave web block.
tabView.webContents.send("webview-new-window", wc.id, details);
return { action: "deny" };
});
wc.on("did-create-window", (popup) => popup.setMenuBarVisibility(false));
});
tabView.webContents.on("before-input-event", (e, input) => {
const waveEvent = adaptFromElectronKeyEvent(input);
Expand Down
8 changes: 8 additions & 0 deletions frontend/app/view/webview/webview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1044,6 +1044,14 @@ const WebView = memo(({ model, onFailLoad, blockRef, initialSrc }: WebViewProps)
const failLoadHandler = (e: any) => {
if (e.errorCode === -3) {
console.warn("Suppressed ERR_ABORTED error", e);
} else if (e.isMainFrame === false) {
// Sub-frame load failures are non-fatal. Web apps routinely load hidden iframes
// that are expected to fail — e.g. OAuth/OIDC silent-auth probes
// (response_mode=web_message, prompt=none), which get blocked by the embedder's
// Cross-Origin-Embedder-Policy and are then handled by the app's auth SDK (it
// falls back to interactive login). A normal browser surfaces these only to the
// SDK, not the user, so don't paint a fatal error over the whole block.
console.warn("Suppressed sub-frame load failure", e.validatedURL, e.errorDescription);
} else {
const errorMessage = `Failed to load ${e.validatedURL}: ${e.errorDescription}`;
console.error(errorMessage);
Expand Down