mirror of
https://github.com/keymanapp/keyman.git
synced 2026-09-26 01:27:42 +00:00
feat(mac): remove mime and extension whitelist
Some checks failed
Keyman Build Summary / Summarize build status checks (push) Has been cancelled
Some checks failed
Keyman Build Summary / Summarize build status checks (push) Has been cancelled
instead check whether content is in the directory with the rest of the package
This commit is contained in:
parent
f608764000
commit
221c07a47a
1 changed files with 53 additions and 53 deletions
|
|
@ -13,9 +13,7 @@ import WebKit
|
|||
import KeymanSettings
|
||||
|
||||
public struct PackageContentWebView: NSViewRepresentable {
|
||||
private static let allowedLocalExtensions = ["pdf", "txt", "png", "jpg", "jpeg"]
|
||||
private static let allowedMimeTypes = ["application/pdf", "text/plain", "image/jpeg", "image/png"]
|
||||
|
||||
|
||||
let packageFileUrl: URL
|
||||
|
||||
// create the AppKit view instance
|
||||
|
|
@ -24,12 +22,18 @@ public struct PackageContentWebView: NSViewRepresentable {
|
|||
|
||||
// Connect the delegate to catch link clicks
|
||||
webView.navigationDelegate = context.coordinator
|
||||
|
||||
|
||||
return webView
|
||||
}
|
||||
|
||||
// update the view when SwiftUI state changes
|
||||
/**
|
||||
* update the view when SwiftUI state changes
|
||||
*/
|
||||
public func updateNSView(_ nsView: WKWebView, context: Context) {
|
||||
// first update the parent in the coordinator so we know which
|
||||
// package we are displaying content for
|
||||
context.coordinator.parent = self
|
||||
|
||||
let request = URLRequest(url: packageFileUrl)
|
||||
|
||||
// only load the request if it's not already loading/loaded to prevent infinite loops
|
||||
|
|
@ -44,19 +48,27 @@ public struct PackageContentWebView: NSViewRepresentable {
|
|||
* Coordinator acts as the WKNavigationDelegate
|
||||
*/
|
||||
public func makeCoordinator() -> Coordinator {
|
||||
Coordinator()
|
||||
Coordinator(self)
|
||||
}
|
||||
|
||||
/**
|
||||
* If a url links to the web rather than locally, open it in the default browser
|
||||
*/
|
||||
@MainActor
|
||||
public class Coordinator: NSObject, WKNavigationDelegate {
|
||||
var parent: PackageContentWebView
|
||||
|
||||
init(_ parent: PackageContentWebView) {
|
||||
self.parent = parent
|
||||
}
|
||||
|
||||
/**
|
||||
* If a url links to the web rather than locally, open it in the default browser
|
||||
* Must force load links in the package content that change the main frame
|
||||
* because WKWebView's security sandbox will block loading of new pages
|
||||
*/
|
||||
public func webView(_ webView: WKWebView,
|
||||
decidePolicyFor navigationAction: WKNavigationAction,
|
||||
decisionHandler: @escaping @MainActor @Sendable (WKNavigationActionPolicy) -> Void) {
|
||||
|
||||
// if not url, cancel
|
||||
|
||||
// if no url, cancel
|
||||
guard let url = navigationAction.request.url else {
|
||||
decisionHandler(.cancel)
|
||||
return
|
||||
|
|
@ -64,59 +76,47 @@ public struct PackageContentWebView: NSViewRepresentable {
|
|||
|
||||
// if not user-activated, pass through, e.g. for redirects
|
||||
guard navigationAction.navigationType == .linkActivated else {
|
||||
decisionHandler(.allow)
|
||||
return
|
||||
}
|
||||
|
||||
// load local files in webview, force-loading some common file types
|
||||
if url.isFileURL {
|
||||
let fileExtension = url.pathExtension.lowercased()
|
||||
|
||||
if PackageContentWebView.allowedLocalExtensions.contains(fileExtension) {
|
||||
// cancel the automatic navigation (which fails silently)
|
||||
decisionHandler(.cancel)
|
||||
|
||||
// force-load the file into the web view frame
|
||||
webView.loadFileURL(url, allowingReadAccessTo: url.deletingLastPathComponent())
|
||||
return
|
||||
}
|
||||
|
||||
print("url not user activated \(url.path())")
|
||||
decisionHandler(.allow)
|
||||
return
|
||||
}
|
||||
|
||||
// handle external links by opening in web browser
|
||||
|
||||
// load local files in webview, force-loading files that are in the same directory
|
||||
if url.isFileURL {
|
||||
let standardizedIncomingUrl = url.standardizedFileURL
|
||||
let packageDirectoryUrl = parent.packageFileUrl.deletingLastPathComponent()
|
||||
let standardizedPackageDirectoryUrl = packageDirectoryUrl.standardizedFileURL
|
||||
|
||||
// check whether the file is from the current package
|
||||
if standardizedIncomingUrl.path.hasPrefix(standardizedPackageDirectoryUrl.path) {
|
||||
decisionHandler(.cancel) // Cancel regular navigation
|
||||
|
||||
// Force load with read permissions of package directory
|
||||
webView.loadFileURL(standardizedIncomingUrl, allowingReadAccessTo: standardizedPackageDirectoryUrl)
|
||||
return
|
||||
} else {
|
||||
// block local files outside of your target directory, not sure how we would receive one
|
||||
decisionHandler(.cancel)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// not a file URL: handle external links by opening in web browser
|
||||
decisionHandler(.cancel)
|
||||
|
||||
|
||||
var externalUrl = url
|
||||
|
||||
|
||||
// strip "link:" prefix if present
|
||||
let urlString = url.absoluteString
|
||||
if urlString.hasPrefix("link:https://") || urlString.hasPrefix("link:http://") {
|
||||
let cleanString = urlString.replacingOccurrences(of: "link:", with: "")
|
||||
if let cleanUrl = URL(string: cleanString) {
|
||||
externalUrl = cleanUrl
|
||||
}
|
||||
let cleanString = urlString.replacingOccurrences(of: "link:", with: "")
|
||||
if let cleanUrl = URL(string: cleanString) {
|
||||
externalUrl = cleanUrl
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Open the external link in the default browser
|
||||
NSWorkspace.shared.open(externalUrl)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow display of some common file types that may be linked in the package help
|
||||
*/
|
||||
public func webView(_ webView: WKWebView,
|
||||
decidePolicyFor navigationResponse: WKNavigationResponse,
|
||||
decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
|
||||
|
||||
if let mimeType = navigationResponse.response.mimeType {
|
||||
if PackageContentWebView.allowedMimeTypes.contains(mimeType) {
|
||||
decisionHandler(.allow)
|
||||
return
|
||||
}
|
||||
}
|
||||
decisionHandler(.allow)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue