From 74179cb534d79d3c785d49866fdcbcd0e80b8e15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20F=C3=B6rtsch?= Date: Fri, 13 Mar 2026 21:23:15 +0100 Subject: [PATCH] add html email rendering with wkwebview, script/tracker blocking Co-Authored-By: Claude Opus 4.6 --- Apps/MagnumOpus/Views/MessageWebView.swift | 64 ++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 Apps/MagnumOpus/Views/MessageWebView.swift diff --git a/Apps/MagnumOpus/Views/MessageWebView.swift b/Apps/MagnumOpus/Views/MessageWebView.swift new file mode 100644 index 0000000..034d3dd --- /dev/null +++ b/Apps/MagnumOpus/Views/MessageWebView.swift @@ -0,0 +1,64 @@ +import SwiftUI +import WebKit + +#if os(macOS) +struct MessageWebView: NSViewRepresentable { + let html: String + + func makeNSView(context: Context) -> WKWebView { + let config = WKWebViewConfiguration() + config.preferences.isElementFullscreenEnabled = false + let prefs = WKWebpagePreferences() + prefs.allowsContentJavaScript = false + config.defaultWebpagePreferences = prefs + let webView = WKWebView(frame: .zero, configuration: config) + return webView + } + + func updateNSView(_ webView: WKWebView, context: Context) { + let sanitized = sanitizeHTML(html) + webView.loadHTMLString(sanitized, baseURL: nil) + } +} +#else +struct MessageWebView: UIViewRepresentable { + let html: String + + func makeUIView(context: Context) -> WKWebView { + let config = WKWebViewConfiguration() + let prefs = WKWebpagePreferences() + prefs.allowsContentJavaScript = false + config.defaultWebpagePreferences = prefs + let webView = WKWebView(frame: .zero, configuration: config) + webView.scrollView.isScrollEnabled = false + return webView + } + + func updateUIView(_ webView: WKWebView, context: Context) { + let sanitized = sanitizeHTML(html) + webView.loadHTMLString(sanitized, baseURL: nil) + } +} +#endif + +private func sanitizeHTML(_ html: String) -> String { + var result = html + let scriptPattern = "]*>[\\s\\S]*?" + result = result.replacingOccurrences(of: scriptPattern, with: "", options: .regularExpression) + let eventPattern = "\\s+on\\w+\\s*=\\s*\"[^\"]*\"" + result = result.replacingOccurrences(of: eventPattern, with: "", options: .regularExpression) + let imgPattern = "(]*?)\\ssrc\\s*=\\s*\"(https?://[^\"]*)\"" + result = result.replacingOccurrences(of: imgPattern, with: "$1 data-blocked-src=\"$2\"", options: .regularExpression) + return """ + + + + + + \(result) + + """ +}