mirror of
https://github.com/Ranchero-Software/NetNewsWire
synced 2025-08-12 06:26:36 +00:00
Now set the correct base URL for each article's webview, and now load app JavaScripts as WebKit "user" scripts.
Setting the real base URL (rather than using a file URL pointing to the app's Resources folder) allows relative URLs to work correctly within the article, such as for images, and is compatible with Cross-Site-Origin policies that restrict use of resources outside of the origin domain. It also implicitly eliminates access to the local file system from within the webview, as the use of a non-file base URL makes WebKit treats the webview's content as being from a remote server, and its default security policy is to then disallow local file access (except with explicit user action, such as drag-and-drop or via an `input` form element). Note: the base URL is currently typically taken from the feed itself (specifically the "link" feed (channel) metadata). That is controlled by the feed author (or a man-in-the-middle attacker). It should perhaps be validated to ensure it's actually an HTTP/HTTPS URL, to prevent security problems. The app-specific JavaScripts - used for fixing styling issues and the like - are now formally loaded as extensions to the web page, "user scripts" in WebKit parlance. They're isolated to their own JavaScript world - meaning they can't be seen or manipulated by JavaScript from the feed article itself, and are more secure as a result. Fixes #4156. Co-Authored-By: Brent Simmons <1297121+brentsimmons@users.noreply.github.com>
This commit is contained in:
@@ -96,6 +96,18 @@ protocol DetailWebViewControllerDelegate: AnyObject {
|
||||
userContentController.add(self, name: MessageName.windowDidScroll)
|
||||
userContentController.add(self, name: MessageName.mouseDidEnter)
|
||||
userContentController.add(self, name: MessageName.mouseDidExit)
|
||||
|
||||
let baseURL = ArticleRenderer.page.baseURL
|
||||
let appScriptsWorld = WKContentWorld.world(name: "NetNewsWire")
|
||||
for fileName in ["main.js", "main_mac.js", "newsfoot.js"] {
|
||||
userContentController.addUserScript(
|
||||
.init(source: try! String(contentsOf: baseURL.appending(path: fileName,
|
||||
directoryHint: .notDirectory)),
|
||||
injectionTime: .atDocumentStart,
|
||||
forMainFrameOnly: true,
|
||||
in: appScriptsWorld))
|
||||
}
|
||||
|
||||
configuration.userContentController = userContentController
|
||||
|
||||
webView = DetailWebView(frame: NSRect.zero, configuration: configuration)
|
||||
@@ -326,7 +338,7 @@ private extension DetailWebViewController {
|
||||
]
|
||||
|
||||
let html = try! MacroProcessor.renderedText(withTemplate: ArticleRenderer.page.html, substitutions: substitutions)
|
||||
webView.loadHTMLString(html, baseURL: ArticleRenderer.page.baseURL)
|
||||
webView.loadHTMLString(html, baseURL: URL(string: rendering.baseURL))
|
||||
}
|
||||
|
||||
func scrollInfo() async -> ScrollInfo? {
|
||||
|
||||
@@ -4,14 +4,6 @@
|
||||
<style>
|
||||
[[style]]
|
||||
</style>
|
||||
<script src="main.js"></script>
|
||||
<script src="main_mac.js"></script>
|
||||
<script src="newsfoot.js" async="async"></script>
|
||||
<script type="text/javascript">
|
||||
document.addEventListener("DOMContentLoaded", function(event) {
|
||||
processPage();
|
||||
})
|
||||
</script>
|
||||
<base href="[[baseURL]]">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -168,3 +168,8 @@ function processPage() {
|
||||
removeWpSmiley()
|
||||
postRenderProcessing();
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function(event) {
|
||||
window.scrollTo(0, [[windowScrollY]]);
|
||||
processPage();
|
||||
})
|
||||
|
||||
@@ -529,6 +529,20 @@ private extension WebViewController {
|
||||
}
|
||||
configuration.setURLSchemeHandler(articleIconSchemeHandler, forURLScheme: ArticleRenderer.imageIconScheme)
|
||||
|
||||
let userContentController = WKUserContentController()
|
||||
let baseURL = ArticleRenderer.page.baseURL
|
||||
let appScriptsWorld = WKContentWorld.world(name: "NetNewsWire")
|
||||
for fileName in ["main.js", "main_ios.js", "newsfoot.js"] {
|
||||
userContentController.addUserScript(
|
||||
.init(source: try! String(contentsOf: baseURL.appending(path: fileName,
|
||||
directoryHint: .notDirectory)),
|
||||
injectionTime: .atDocumentStart,
|
||||
forMainFrameOnly: true,
|
||||
in: appScriptsWorld))
|
||||
}
|
||||
|
||||
configuration.userContentController = userContentController
|
||||
|
||||
let webView = WKWebView(frame: self.view.bounds, configuration: configuration)
|
||||
webView.isOpaque = false;
|
||||
webView.backgroundColor = .clear;
|
||||
@@ -591,8 +605,8 @@ private extension WebViewController {
|
||||
]
|
||||
|
||||
let html = try! MacroProcessor.renderedText(withTemplate: ArticleRenderer.page.html, substitutions: substitutions)
|
||||
webView.loadHTMLString(html, baseURL: ArticleRenderer.page.baseURL)
|
||||
|
||||
webView.loadHTMLString(html, baseURL: URL(string: rendering.baseURL))
|
||||
|
||||
}
|
||||
|
||||
func finalScrollPosition(scrollingUp: Bool) -> CGFloat {
|
||||
|
||||
@@ -5,15 +5,6 @@
|
||||
<style>
|
||||
[[style]]
|
||||
</style>
|
||||
<script src="main.js"></script>
|
||||
<script src="main_ios.js"></script>
|
||||
<script src="newsfoot.js" async="async"></script>
|
||||
<script type="text/javascript">
|
||||
document.addEventListener("DOMContentLoaded", function(event) {
|
||||
window.scrollTo(0, [[windowScrollY]]);
|
||||
processPage();
|
||||
})
|
||||
</script>
|
||||
<base href="[[baseURL]]">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
Reference in New Issue
Block a user