diff --git a/Sources/Panels/BrowserPanel.swift b/Sources/Panels/BrowserPanel.swift index 974514ea..ca100a99 100644 --- a/Sources/Panels/BrowserPanel.swift +++ b/Sources/Panels/BrowserPanel.swift @@ -239,7 +239,15 @@ enum BrowserInsecureHTTPSettings { private static func trimHost(_ raw: String) -> String? { let trimmed = raw.trimmingCharacters(in: CharacterSet(charactersIn: ".")) - return trimmed.isEmpty ? nil : trimmed + guard !trimmed.isEmpty else { return nil } + + // Canonicalize IDN entries (e.g. bücher.example -> xn--bcher-kva.example) + // so user-entered allowlist patterns compare against URL.host consistently. + if let canonicalized = URL(string: "https://\(trimmed)")?.host { + return canonicalized + } + + return trimmed } } diff --git a/cmuxTests/CmuxWebViewKeyEquivalentTests.swift b/cmuxTests/CmuxWebViewKeyEquivalentTests.swift index bc169203..7ee933a4 100644 --- a/cmuxTests/CmuxWebViewKeyEquivalentTests.swift +++ b/cmuxTests/CmuxWebViewKeyEquivalentTests.swift @@ -2960,4 +2960,9 @@ final class BrowserHostWhitelistTests: XCTestCase { defaults.set("http://\n*.\n", forKey: BrowserLinkOpenSettings.browserHostWhitelistKey) XCTAssertFalse(BrowserLinkOpenSettings.hostMatchesWhitelist("example.com", defaults: defaults)) } + + func testUnicodeWhitelistEntryMatchesPunycodeHost() { + defaults.set("b\\u{00FC}cher.example", forKey: BrowserLinkOpenSettings.browserHostWhitelistKey) + XCTAssertTrue(BrowserLinkOpenSettings.hostMatchesWhitelist("xn--bcher-kva.example", defaults: defaults)) + } }