-
Notifications
You must be signed in to change notification settings - Fork 426
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Malicious site protection - extract special error page navigation logic #3624
Merged
alessandroboron
merged 7 commits into
alessandro/malicious-site-protection
from
alessandro/malicious-site-protection-navigation
Dec 2, 2024
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
62fe8f5
Add SpecialErrorPage navigation handlers
alessandroboron f11301e
Update TabViewController to use SpecialErrorPageNavigationHandler
alessandroboron 43d6335
Update and add tests for SpecialErrorPageNavigationHandler
alessandroboron 4d4f428
Fix unit tests crash
alessandroboron c3815f5
Fix lint warnings
alessandroboron cdf5546
Refactor Special Error model
alessandroboron b77eb5a
Fix PR comments
alessandroboron File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
56 changes: 56 additions & 0 deletions
56
DuckDuckGo/MaliciousSiteProtection/MaliciousSiteProtectionManager.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
// | ||
// MaliciousSiteProtectionManager.swift | ||
// DuckDuckGo | ||
// | ||
// Copyright © 2024 DuckDuckGo. All rights reserved. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
// | ||
|
||
import Foundation | ||
|
||
final class MaliciousSiteProtectionManager: MaliciousSiteDetecting { | ||
|
||
func evaluate(_ url: URL) async -> ThreatKind? { | ||
try? await Task.sleep(interval: 0.3) | ||
return .none | ||
} | ||
|
||
} | ||
|
||
// MARK: - To Remove | ||
|
||
// These entities are copied from BSK and they will be used to mock the library | ||
import SpecialErrorPages | ||
|
||
protocol MaliciousSiteDetecting { | ||
func evaluate(_ url: URL) async -> ThreatKind? | ||
} | ||
|
||
public enum ThreatKind: String, CaseIterable, CustomStringConvertible { | ||
public var description: String { rawValue } | ||
|
||
case phishing | ||
case malware | ||
} | ||
|
||
public extension ThreatKind { | ||
|
||
var errorPageType: SpecialErrorKind { | ||
switch self { | ||
case .malware: .phishing // WIP in BSK | ||
case .phishing: .phishing | ||
} | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
// | ||
// SpecialErrorModel.swift | ||
// DuckDuckGo | ||
// | ||
// Copyright © 2024 DuckDuckGo. All rights reserved. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
// | ||
|
||
import Foundation | ||
import SpecialErrorPages | ||
|
||
struct SpecialErrorModel: Equatable { | ||
let url: URL | ||
let errorData: SpecialErrorData | ||
} | ||
|
||
struct SSLSpecialError { | ||
let type: SSLErrorType | ||
let error: SpecialErrorModel | ||
} |
36 changes: 36 additions & 0 deletions
36
DuckDuckGo/SpecialErrorPage/SpecialErrorPageInterfaces/SpecialErrorPageActionHandler.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
// | ||
// SpecialErrorPageActionHandler.swift | ||
// DuckDuckGo | ||
// | ||
// Copyright © 2024 DuckDuckGo. All rights reserved. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
// | ||
|
||
import Foundation | ||
|
||
/// A type that defines actions for handling special error pages. | ||
/// | ||
/// This protocol is intended to be adopted by types that need to manage user interactions | ||
/// with special error pages, such as navigating to a site, leaving a site, or presenting | ||
/// advanced information related to the error. | ||
protocol SpecialErrorPageActionHandler { | ||
/// Handles the action of navigating to the site associated with the error page | ||
func visitSite() | ||
|
||
/// Handles the action of leaving the site associated with the error page | ||
func leaveSite() | ||
|
||
/// Handles the action of requesting more detailed information about the error | ||
func advancedInfoPresented() | ||
} |
40 changes: 40 additions & 0 deletions
40
DuckDuckGo/SpecialErrorPage/SpecialErrorPageInterfaces/SpecialErrorPageContextHandling.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
// | ||
// SpecialErrorPageContextHandling.swift | ||
// DuckDuckGo | ||
// | ||
// Copyright © 2024 DuckDuckGo. All rights reserved. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
// | ||
|
||
import Foundation | ||
import WebKit | ||
import SpecialErrorPages | ||
|
||
/// A type that defines the base functionality for handling navigation related to special error pages. | ||
protocol SpecialErrorPageContextHandling: AnyObject { | ||
/// The delegate that handles navigation actions for special error pages. | ||
var delegate: SpecialErrorPageNavigationDelegate? { get set } | ||
|
||
/// A Boolean value indicating whether the special error page is currently visible. | ||
var isSpecialErrorPageVisible: Bool { get } | ||
|
||
/// The URL that failed to load, if any. | ||
var failedURL: URL? { get } | ||
|
||
/// Attaches a web view to the special error page handling. | ||
func attachWebView(_ webView: WKWebView) | ||
|
||
/// Sets the user script for the special error page. | ||
func setUserScript(_ userScript: SpecialErrorPageUserScript?) | ||
} |
26 changes: 26 additions & 0 deletions
26
...ckGo/SpecialErrorPage/SpecialErrorPageInterfaces/SpecialErrorPageNavigationDelegate.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
// | ||
// SpecialErrorPageNavigationDelegate.swift | ||
// DuckDuckGo | ||
// | ||
// Copyright © 2024 DuckDuckGo. All rights reserved. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
// | ||
|
||
import Foundation | ||
|
||
/// A delegate for handling navigation actions related to special error pages. | ||
protocol SpecialErrorPageNavigationDelegate: AnyObject { | ||
/// Asks the delegate to close the special error page tab when the web view can't navigate back. | ||
func closeSpecialErrorPageTab() | ||
} |
69 changes: 69 additions & 0 deletions
69
DuckDuckGo/SpecialErrorPage/SpecialErrorPageInterfaces/WebViewNavigationHandling.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
// | ||
// WebViewNavigationHandling.swift | ||
// DuckDuckGo | ||
// | ||
// Copyright © 2024 DuckDuckGo. All rights reserved. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
// | ||
|
||
import Foundation | ||
import WebKit | ||
|
||
// MARK: - WebViewNavigation | ||
|
||
/// For testing purposes. | ||
protocol WebViewNavigation {} | ||
|
||
// Used in tests. WKNavigation() crashes on deinit when initialising it manually. | ||
// As workaround we used to Swizzle the implementation of deinit in tests. | ||
// The problem with that approach is that when running different test suites it is possible that unrelated tests re-set the original implementation of deinit while other tests are running. | ||
// This cause the app to crash as the original implementation is executed. | ||
// Defining a protocol for WKNavigation and using mocks such as DummyWKNavigation in tests resolves the problem. | ||
extension WKNavigation: WebViewNavigation {} | ||
|
||
// MARK: - WebViewNavigationHandling | ||
|
||
/// A protocol that defines methods for handling navigation events of `WKWebView`. | ||
protocol WebViewNavigationHandling: AnyObject { | ||
/// Decides whether to cancel navigation to prevent opening a site and show a special error page based on the specified action information. | ||
/// | ||
/// - Parameters: | ||
/// - navigationAction: Details about the action that triggered the navigation request. | ||
/// - webView: The web view from which the navigation request began. | ||
/// - Returns: A Boolean value that indicates whether the navigation action was handled. | ||
func handleSpecialErrorNavigation(navigationAction: WKNavigationAction, webView: WKWebView) async -> Bool | ||
|
||
/// Handles authentication challenges received by the web view. | ||
/// | ||
/// - Parameters: | ||
/// - webView: The web view that receives the authentication challenge. | ||
/// - challenge: The authentication challenge. | ||
/// - completionHandler: A completion handler block to execute with the response. | ||
func handleWebView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) | ||
|
||
/// Handles failures during provisional navigation. | ||
/// | ||
/// - Parameters: | ||
/// - webView: The `WKWebView` instance that failed the navigation. | ||
/// - navigation: The navigation object for the operation. | ||
/// - error: The error that occurred. | ||
func handleWebView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WebViewNavigation, withError error: NSError) | ||
|
||
/// Handles the successful completion of a navigation in the web view. | ||
/// | ||
/// - Parameters: | ||
/// - webView: The web view that loaded the content. | ||
/// - navigation: The navigation object that finished. | ||
func handleWebView(_ webView: WKWebView, didFinish navigation: WebViewNavigation) | ||
} |
83 changes: 83 additions & 0 deletions
83
DuckDuckGo/SpecialErrorPage/SpecialErrorPageNavigationHandler+MaliciousSite.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
// | ||
// SpecialErrorPageNavigationHandler+MaliciousSite.swift | ||
// DuckDuckGo | ||
// | ||
// Copyright © 2024 DuckDuckGo. All rights reserved. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
// | ||
|
||
import Foundation | ||
import BrowserServicesKit | ||
import Core | ||
import SpecialErrorPages | ||
import WebKit | ||
|
||
enum MaliciousSiteProtectionNavigationResult: Equatable { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This class will encapsulate MaliciousSiteProtection logic to evaluate if a site is malicious and will handle its internal state to bypass URLs. |
||
case navigationHandled(SpecialErrorModel) | ||
case navigationNotHandled | ||
} | ||
|
||
protocol MaliciousSiteProtectionNavigationHandling: AnyObject { | ||
/// Decides whether to cancel navigation to prevent opening the YouTube app from the web view. | ||
/// | ||
/// - Parameters: | ||
/// - navigationAction: The navigation action to evaluate. | ||
/// - webView: The web view where navigation is occurring. | ||
/// - Returns: `true` if the navigation should be canceled, `false` otherwise. | ||
func handleMaliciousSiteProtectionNavigation(for navigationAction: WKNavigationAction, webView: WKWebView) async -> MaliciousSiteProtectionNavigationResult | ||
} | ||
|
||
final class MaliciousSiteProtectionNavigationHandler { | ||
private let maliciousSiteProtectionManager: MaliciousSiteDetecting | ||
private let storageCache: StorageCache | ||
|
||
init( | ||
maliciousSiteProtectionManager: MaliciousSiteDetecting = MaliciousSiteProtectionManager(), | ||
storageCache: StorageCache = AppDependencyProvider.shared.storageCache | ||
) { | ||
self.maliciousSiteProtectionManager = maliciousSiteProtectionManager | ||
self.storageCache = storageCache | ||
} | ||
} | ||
|
||
// MARK: - MaliciousSiteProtectionNavigationHandling | ||
|
||
extension MaliciousSiteProtectionNavigationHandler: MaliciousSiteProtectionNavigationHandling { | ||
|
||
@MainActor | ||
func handleMaliciousSiteProtectionNavigation(for navigationAction: WKNavigationAction, webView: WKWebView) async -> MaliciousSiteProtectionNavigationResult { | ||
// Implement logic to use `maliciousSiteProtectionManager.evaluate(url)` | ||
// Return navigationNotHandled for the time being | ||
return .navigationNotHandled | ||
} | ||
|
||
} | ||
|
||
// MARK: - SpecialErrorPageActionHandler | ||
|
||
extension MaliciousSiteProtectionNavigationHandler: SpecialErrorPageActionHandler { | ||
|
||
func visitSite() { | ||
// Fire Pixel | ||
} | ||
|
||
func leaveSite() { | ||
// Fire Pixel | ||
} | ||
|
||
func advancedInfoPresented() { | ||
// Fire Pixel | ||
} | ||
|
||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Implementation of this class will come in a subsequent PR.
This was used to mock the BSK library and assert that the special error page was rendered.