Skip to content
This repository was archived by the owner on Feb 24, 2025. It is now read-only.

Commit 1472616

Browse files
committed
Validate duck.ai URL
1 parent cf2d339 commit 1472616

File tree

3 files changed

+56
-3
lines changed

3 files changed

+56
-3
lines changed

LocalPackages/AIChat/Sources/AIChat/AIChatWebViewController.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ extension AIChatWebViewController: WKNavigationDelegate {
109109

110110
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction) async -> WKNavigationActionPolicy {
111111
if let url = navigationAction.request.url {
112-
if url == chatModel.aiChatURL || navigationAction.targetFrame?.isMainFrame == false {
112+
if url.isDuckAIURL || navigationAction.targetFrame?.isMainFrame == false {
113113
return .allow
114114
} else {
115115
delegate?.aiChatWebViewController(self, didRequestToLoad: url)

LocalPackages/AIChat/Sources/AIChat/URL+Extension.swift

+13
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,17 @@ extension URL {
3232
urlComponents.queryItems = queryItems
3333
return urlComponents.url ?? self
3434
}
35+
36+
var isDuckAIURL: Bool {
37+
guard let host = self.host, host == "duckduckgo.com" else {
38+
return false
39+
}
40+
41+
guard let urlComponents = URLComponents(url: self, resolvingAgainstBaseURL: false),
42+
let queryItems = urlComponents.queryItems else {
43+
return false
44+
}
45+
46+
return queryItems.contains { $0.name == "ia" && $0.value == "chat" }
47+
}
3548
}

LocalPackages/AIChat/Tests/URLQueryItemTests.swift LocalPackages/AIChat/Tests/URLExtensionTests.swift

+42-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//
2-
// URLQueryItemTests.swift
2+
// URLExtensionTests.swift
33
// DuckDuckGo
44
//
55
// Copyright © 2022 DuckDuckGo. All rights reserved.
@@ -20,7 +20,7 @@
2020
import XCTest
2121
@testable import AIChat
2222

23-
class URLQueryItemTests: XCTestCase {
23+
class URLExtensionTests: XCTestCase {
2424

2525
func testAddingQueryItemToEmptyURL() {
2626
let url = URL(string: "https://example.com")!
@@ -81,6 +81,46 @@ class URLQueryItemTests: XCTestCase {
8181
XCTAssertEqual(result.host, "example.com")
8282
XCTAssertEqual(result.queryItemsDictionary, ["key": ""])
8383
}
84+
85+
func testIsDuckAIURLWithValidURL() {
86+
if let url = URL(string: "https://duckduckgo.com/?ia=chat") {
87+
XCTAssertTrue(url.isDuckAIURL, "The URL should be identified as a DuckDuckGo AI URL.")
88+
} else {
89+
XCTFail("Failed to create URL from string.")
90+
}
91+
}
92+
93+
func testIsDuckAIURLWithInvalidDomain() {
94+
if let url = URL(string: "https://example.com/?ia=chat") {
95+
XCTAssertFalse(url.isDuckAIURL, "The URL should not be identified as a DuckDuckGo AI URL due to the domain.")
96+
} else {
97+
XCTFail("Failed to create URL from string.")
98+
}
99+
}
100+
101+
func testIsDuckAIURLWithMissingQueryItem() {
102+
if let url = URL(string: "https://duckduckgo.com/") {
103+
XCTAssertFalse(url.isDuckAIURL, "The URL should not be identified as a DuckDuckGo AI URL due to missing query item.")
104+
} else {
105+
XCTFail("Failed to create URL from string.")
106+
}
107+
}
108+
109+
func testIsDuckAIURLWithDifferentQueryItem() {
110+
if let url = URL(string: "https://duckduckgo.com/?ia=search") {
111+
XCTAssertFalse(url.isDuckAIURL, "The URL should not be identified as a DuckDuckGo AI URL due to different query item value.")
112+
} else {
113+
XCTFail("Failed to create URL from string.")
114+
}
115+
}
116+
117+
func testIsDuckAIURLWithAdditionalQueryItems() {
118+
if let url = URL(string: "https://duckduckgo.com/?ia=chat&other=param") {
119+
XCTAssertTrue(url.isDuckAIURL, "The URL should be identified as a DuckDuckGo AI URL even with additional query items.")
120+
} else {
121+
XCTFail("Failed to create URL from string.")
122+
}
123+
}
84124
}
85125

86126
extension URL {

0 commit comments

Comments
 (0)