@@ -1169,6 +1169,7 @@ final class BrowserPanel: Panel, ObservableObject {
11691169 private var navigationDelegate : BrowserNavigationDelegate ?
11701170 private var uiDelegate : BrowserUIDelegate ?
11711171 private var downloadDelegate : BrowserDownloadDelegate ?
1172+ private var webAuthnCoordinator : BrowserWebAuthnCoordinator ?
11721173 private var webViewObservers : [ NSKeyValueObservation ] = [ ]
11731174 private var activeDownloadCount : Int = 0
11741175
@@ -1486,6 +1487,17 @@ final class BrowserPanel: Panel, ObservableObject {
14861487 forMainFrameOnly: true
14871488 )
14881489 )
1490+ // WebAuthn can originate from same-origin child frames. The native
1491+ // bridge rejects first-time authorization requests from cross-origin
1492+ // subframes before touching the shared browser authorization state.
1493+ configuration. userContentController. addUserScript (
1494+ WKUserScript (
1495+ source: BrowserWebAuthnBridgeContract . scriptSource,
1496+ injectionTime: . atDocumentStart,
1497+ forMainFrameOnly: false ,
1498+ in: . page
1499+ )
1500+ )
14891501 }
14901502
14911503 private func bindWebView( _ webView: ProgramaWebView ) {
@@ -1504,6 +1516,9 @@ final class BrowserPanel: Panel, ObservableObject {
15041516 webView. uiDelegate = uiDelegate
15051517 setupObservers ( for: webView)
15061518 setupReactGrabMessageHandler ( for: webView)
1519+ let webAuthnCoordinator = BrowserWebAuthnCoordinator ( )
1520+ webAuthnCoordinator. install ( on: webView)
1521+ self . webAuthnCoordinator = webAuthnCoordinator
15071522 setupIMECompositionTracking ( for: webView)
15081523 }
15091524
@@ -1800,6 +1815,8 @@ final class BrowserPanel: Panel, ObservableObject {
18001815 faviconTask = nil
18011816 faviconRefreshGeneration &+= 1
18021817 BrowserWindowPortalRegistry . detach ( webView: previousWebView)
1818+ webAuthnCoordinator? . uninstall ( from: previousWebView)
1819+ webAuthnCoordinator = nil
18031820 previousWebView. stopLoading ( )
18041821 previousWebView. navigationDelegate = nil
18051822 previousWebView. uiDelegate = nil
@@ -2155,6 +2172,8 @@ final class BrowserPanel: Panel, ObservableObject {
21552172 faviconTask = nil
21562173 faviconRefreshGeneration &+= 1
21572174 BrowserWindowPortalRegistry . detach ( webView: oldWebView)
2175+ webAuthnCoordinator? . uninstall ( from: oldWebView)
2176+ webAuthnCoordinator = nil
21582177 oldWebView. stopLoading ( )
21592178 oldWebView. navigationDelegate = nil
21602179 oldWebView. uiDelegate = nil
@@ -2296,6 +2315,8 @@ final class BrowserPanel: Panel, ObservableObject {
22962315 popup. closePopup ( )
22972316 }
22982317
2318+ webAuthnCoordinator? . uninstall ( from: webView)
2319+ webAuthnCoordinator = nil
22992320 webView. stopLoading ( )
23002321 webView. navigationDelegate = nil
23012322 webView. uiDelegate = nil
@@ -2907,8 +2928,11 @@ final class BrowserPanel: Panel, ObservableObject {
29072928 }
29082929 webViewObservers. removeAll ( )
29092930 webViewCancellables. removeAll ( )
2931+ let webAuthnCoordinator = webAuthnCoordinator
2932+ self . webAuthnCoordinator = nil
29102933 let webView = webView
29112934 Task { @MainActor in
2935+ webAuthnCoordinator? . uninstall ( from: webView)
29122936 BrowserWindowPortalRegistry . detach ( webView: webView)
29132937 }
29142938 }
@@ -2999,6 +3023,8 @@ extension BrowserPanel {
29993023 webViewObservers. removeAll ( )
30003024 webViewCancellables. removeAll ( )
30013025 BrowserWindowPortalRegistry . detach ( webView: oldWebView)
3026+ webAuthnCoordinator? . uninstall ( from: oldWebView)
3027+ webAuthnCoordinator = nil
30023028 oldWebView. stopLoading ( )
30033029 oldWebView. navigationDelegate = nil
30043030 oldWebView. uiDelegate = nil
0 commit comments