diff --git a/ios/brave-ios/Sources/Brave/Frontend/Browser/User Scripts/ScriptFactory.swift b/ios/brave-ios/Sources/Brave/Frontend/Browser/User Scripts/ScriptFactory.swift index 94113d17f791..443c8ada664d 100644 --- a/ios/brave-ios/Sources/Brave/Frontend/Browser/User Scripts/ScriptFactory.swift +++ b/ios/brave-ios/Sources/Brave/Frontend/Browser/User Scripts/ScriptFactory.swift @@ -194,7 +194,7 @@ class ScriptFactory { sourceWrapper = sourceWrapper.replacingOccurrences(of: "$", with: source) sourceWrapper = sourceWrapper.replacingOccurrences( of: "$", - with: configuration.frameURL.domainURL.absoluteString + with: configuration.frameURL.windowOriginURL.absoluteString ) // when `isMainFrame` is true, we still need to inject to all frames to handle `about:blank` first-party frames resultingScript = WKUserScript( diff --git a/ios/brave-ios/Sources/BraveShared/Extensions/URLExtensions.swift b/ios/brave-ios/Sources/BraveShared/Extensions/URLExtensions.swift index 7a4ff24d36f9..27f01dc52660 100644 --- a/ios/brave-ios/Sources/BraveShared/Extensions/URLExtensions.swift +++ b/ios/brave-ios/Sources/BraveShared/Extensions/URLExtensions.swift @@ -185,6 +185,15 @@ extension URL { return renderedString.bidiBaseDirection == .leftToRight } + + /// Matches what `window.origin` would return in javascript. + public var windowOriginURL: URL { + var components = URLComponents() + components.scheme = self.scheme + components.port = self.port + components.host = self.host + return components.url ?? self + } } extension InternalURL { diff --git a/ios/brave-ios/Tests/BraveSharedTests/URLExtensionTests.swift b/ios/brave-ios/Tests/BraveSharedTests/URLExtensionTests.swift index 7ed457576c2f..9df4bc8ab479 100644 --- a/ios/brave-ios/Tests/BraveSharedTests/URLExtensionTests.swift +++ b/ios/brave-ios/Tests/BraveSharedTests/URLExtensionTests.swift @@ -5,6 +5,7 @@ import Foundation import Shared +import WebKit import XCTest class URLExtensionTests: XCTestCase { @@ -135,4 +136,58 @@ class URLExtensionTests: XCTestCase { embeddedURL ) } + + // Test that `windowOriginURL` returns the same value as `window.origin`. + @MainActor func testWindowOriginURL() async { + let testURLs = [ + // multiple subdomains + (URL(string: "https://one.two.three.example.com")!, "https://one.two.three.example.com"), + // trailing slash + (URL(string: "https://example.com/")!, "https://example.com"), + // query + (URL(string: "https://www.example.com/?v=1234567")!, "https://www.example.com"), + // match + (URL(string: "https://www.example.com")!, "https://www.example.com"), + // punycode + (URL(string: "http://Дом.ru/")!, "http://xn--d1aqf.ru"), + // punycode + (URL(string: "http://Дoм.ru/")!, "http://xn--o-gtbz.ru"), + ] + + let webView = WKWebView() + for (value, expected) in testURLs { + do { + let expectation = XCTestExpectation(description: "didFinish") + let navigationDelegate = NavigationDelegate(didFinish: { + expectation.fulfill() + }) + webView.navigationDelegate = navigationDelegate + webView.loadHTMLString("", baseURL: value) + + // await load of html + await fulfillment(of: [expectation], timeout: 2) + + guard let result = try await webView.evaluateJavaScript("window.origin") as? String else { + XCTFail("Expected a String result") + return + } + XCTAssertEqual(result, expected) + XCTAssertEqual(result, value.windowOriginURL.absoluteString) + } catch { + XCTFail("Expected a valid `window.origin`") + } + } + } +} + +private class NavigationDelegate: NSObject, WKNavigationDelegate { + private var didFinish: () -> Void + + init(didFinish: @escaping () -> Void) { + self.didFinish = didFinish + } + + func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { + didFinish() + } }