Skip to content

Commit 495a327

Browse files
Share browser context with OAuth popups (manaflow-ai#1600)
* Add popup browser context regression tests * Share browser context with OAuth popups --------- Co-authored-by: Lawrence Chen <lawrencecchen@users.noreply.github.com>
1 parent 8ed6e77 commit 495a327

3 files changed

Lines changed: 85 additions & 21 deletions

File tree

Sources/Panels/BrowserPanel.swift

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2447,19 +2447,42 @@ final class BrowserPanel: Panel, ObservableObject {
24472447
websiteDataStore: WKWebsiteDataStore? = nil
24482448
) -> CmuxWebView {
24492449
let config = WKWebViewConfiguration()
2450-
config.processPool = BrowserPanel.sharedProcessPool
2451-
config.mediaTypesRequiringUserActionForPlayback = []
2450+
configureWebViewConfiguration(
2451+
config,
2452+
websiteDataStore: websiteDataStore ?? BrowserProfileStore.shared.websiteDataStore(for: profileID)
2453+
)
2454+
2455+
let webView = CmuxWebView(frame: .zero, configuration: config)
2456+
webView.allowsBackForwardNavigationGestures = true
2457+
if #available(macOS 13.3, *) {
2458+
webView.isInspectable = true
2459+
}
2460+
// Match the empty-page background to the terminal theme so newly-created browsers
2461+
// don't flash white before content loads.
2462+
webView.underPageBackgroundColor = GhosttyBackgroundTheme.currentColor()
2463+
// Always present as Safari.
2464+
webView.customUserAgent = BrowserUserAgentSettings.safariUserAgent
2465+
return webView
2466+
}
2467+
2468+
static func configureWebViewConfiguration(
2469+
_ configuration: WKWebViewConfiguration,
2470+
websiteDataStore: WKWebsiteDataStore,
2471+
processPool: WKProcessPool = BrowserPanel.sharedProcessPool
2472+
) {
2473+
configuration.processPool = processPool
2474+
configuration.mediaTypesRequiringUserActionForPlayback = []
24522475
// Ensure browser cookies/storage persist across navigations and launches.
24532476
// This reduces repeated consent/bot-challenge flows on sites like Google.
2454-
config.websiteDataStore = websiteDataStore ?? BrowserProfileStore.shared.websiteDataStore(for: profileID)
2477+
configuration.websiteDataStore = websiteDataStore
24552478

24562479
// Enable developer extras (DevTools)
2457-
config.preferences.setValue(true, forKey: "developerExtrasEnabled")
2480+
configuration.preferences.setValue(true, forKey: "developerExtrasEnabled")
24582481

24592482
// Enable JavaScript
2460-
config.defaultWebpagePreferences.allowsContentJavaScript = true
2483+
configuration.defaultWebpagePreferences.allowsContentJavaScript = true
24612484
// Keep browser console/error/dialog telemetry active from document start on every navigation.
2462-
config.userContentController.addUserScript(
2485+
configuration.userContentController.addUserScript(
24632486
WKUserScript(
24642487
source: Self.telemetryHookBootstrapScriptSource,
24652488
injectionTime: .atDocumentStart,
@@ -2468,25 +2491,13 @@ final class BrowserPanel: Panel, ObservableObject {
24682491
)
24692492
// Track the last editable focused element continuously so omnibar exit can
24702493
// restore page input focus even if capture runs after first-responder handoff.
2471-
config.userContentController.addUserScript(
2494+
configuration.userContentController.addUserScript(
24722495
WKUserScript(
24732496
source: Self.addressBarFocusTrackingBootstrapScript,
24742497
injectionTime: .atDocumentStart,
24752498
forMainFrameOnly: false
24762499
)
24772500
)
2478-
2479-
let webView = CmuxWebView(frame: .zero, configuration: config)
2480-
webView.allowsBackForwardNavigationGestures = true
2481-
if #available(macOS 13.3, *) {
2482-
webView.isInspectable = true
2483-
}
2484-
// Match the empty-page background to the terminal theme so newly-created browsers
2485-
// don't flash white before content loads.
2486-
webView.underPageBackgroundColor = GhosttyBackgroundTheme.currentColor()
2487-
// Always present as Safari.
2488-
webView.customUserAgent = BrowserUserAgentSettings.safariUserAgent
2489-
return webView
24902501
}
24912502

24922503
private func bindWebView(_ webView: CmuxWebView) {

Sources/Panels/BrowserPopupWindowController.swift

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,13 +92,24 @@ final class BrowserPopupWindowController: NSObject, NSWindowDelegate {
9292
self.parentPopupController = parentPopupController
9393
self.nestingDepth = nestingDepth
9494

95-
// Create popup web view with WebKit's supplied configuration (preserves
96-
// internal browsing-context state for opener linkage / postMessage).
95+
let browserContextSource = parentPopupController?.webView.configuration ?? openerPanel?.webView.configuration
96+
if let browserContextSource {
97+
BrowserPanel.configureWebViewConfiguration(
98+
configuration,
99+
websiteDataStore: browserContextSource.websiteDataStore,
100+
processPool: browserContextSource.processPool
101+
)
102+
}
103+
104+
// Create popup web view with WebKit's supplied configuration after
105+
// overlaying the opener's browser context so OAuth popups keep cmux's
106+
// shared cookie/storage scope and opener linkage.
97107
let webView = CmuxWebView(frame: .zero, configuration: configuration)
98108
webView.allowsBackForwardNavigationGestures = true
99109
if #available(macOS 13.3, *) {
100110
webView.isInspectable = true
101111
}
112+
webView.underPageBackgroundColor = GhosttyBackgroundTheme.currentColor()
102113
webView.customUserAgent = BrowserUserAgentSettings.safariUserAgent
103114
self.webView = webView
104115

cmuxTests/GhosttyConfigTests.swift

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,6 +1003,48 @@ final class GhosttyTerminalStartupEnvironmentTests: XCTestCase {
10031003
}
10041004
}
10051005

1006+
@MainActor
1007+
final class BrowserPanelPopupContextTests: XCTestCase {
1008+
func testFloatingPopupInheritsOpenerBrowserContext() throws {
1009+
let panel = BrowserPanel(workspaceId: UUID(), isRemoteWorkspace: false)
1010+
let popupWebView = try XCTUnwrap(
1011+
panel.createFloatingPopup(
1012+
configuration: WKWebViewConfiguration(),
1013+
windowFeatures: WKWindowFeatures()
1014+
)
1015+
)
1016+
defer { popupWebView.window?.close() }
1017+
1018+
XCTAssertTrue(
1019+
popupWebView.configuration.processPool === panel.webView.configuration.processPool
1020+
)
1021+
XCTAssertTrue(
1022+
popupWebView.configuration.websiteDataStore === panel.webView.configuration.websiteDataStore
1023+
)
1024+
}
1025+
1026+
func testFloatingPopupInheritsRemoteWorkspaceWebsiteDataStore() throws {
1027+
let remoteWorkspaceId = UUID()
1028+
let panel = BrowserPanel(
1029+
workspaceId: remoteWorkspaceId,
1030+
isRemoteWorkspace: true,
1031+
remoteWebsiteDataStoreIdentifier: remoteWorkspaceId
1032+
)
1033+
let popupWebView = try XCTUnwrap(
1034+
panel.createFloatingPopup(
1035+
configuration: WKWebViewConfiguration(),
1036+
windowFeatures: WKWindowFeatures()
1037+
)
1038+
)
1039+
defer { popupWebView.window?.close() }
1040+
1041+
XCTAssertTrue(
1042+
popupWebView.configuration.websiteDataStore === panel.webView.configuration.websiteDataStore
1043+
)
1044+
XCTAssertFalse(popupWebView.configuration.websiteDataStore === WKWebsiteDataStore.default())
1045+
}
1046+
}
1047+
10061048
@MainActor
10071049
final class BrowserPanelRemoteStoreTests: XCTestCase {
10081050
func testRemoteWorkspacePanelsShareWorkspaceScopedWebsiteDataStore() {

0 commit comments

Comments
 (0)