Rabbit Remote Control 0.1.0-bate16
Loading...
Searching...
No Matches
SystemProtocolHandler.cpp
1#include <QFileInfo>
2#include <QMessageBox>
3#include <QUrl>
4#include <QWebEngineUrlRequestJob>
5#include <QLoggingCategory>
6#include <QDesktopServices>
7#include <QBuffer>
8#include "ProtocolManager.h"
9#include "SystemProtocolHandler.h"
10
11static Q_LOGGING_CATEGORY(log, "WebBrowser.SystemProtocolHandler")
12void CSystemProtocolHandler::requestStarted(QWebEngineUrlRequestJob *request)
13{
14 QUrl url = request->requestUrl();
15 qDebug(log) << "Intercepting" << m_scheme << ":" << url.toString();
16
17 // 检查 URL 是否有效
18 if (!url.isValid()) {
19 qWarning(log) << "Invalid URL:" << url;
20 request->fail(QWebEngineUrlRequestJob::UrlInvalid);
21 return;
22 }
23
24 // 安全验证:防止恶意 URL
25 if (!isUrlSafe(url)) {
26 qWarning(log) << "Blocked potentially unsafe URL:" << url;
27 request->fail(QWebEngineUrlRequestJob::UrlInvalid);
28 return;
29 }
30
32 QString szHandler = mgr.getDefaultHandlerForProtocol(url.scheme());
33 if(szHandler.isEmpty()) {
34 qCritical(log) << "Don't find handler" << url.scheme();
35 return;
36 }
37 szHandler = szHandler.section(' ', 0, 0).trimmed();
38 int nRet = QMessageBox::question(
39 nullptr, url.scheme(),
40 tr("Use the %1 to open %2")
41 .arg(szHandler)
42 .arg(url.toString()),
43 QMessageBox::Yes|QMessageBox::No,
44 QMessageBox::No);
45 if(QMessageBox::Yes == nRet) {
46 // 方法1:使用 QDesktopServices 打开(会触发系统默认处理)
47 QDesktopServices::openUrl(url);
48
49 // 方法2:直接重定向到外部(如果需要)
50 // 注意:这不会在 WebView 中显示,而是打开外部应用
51 }
52
53 QByteArray emptyData = generateResponsePage(url, QMessageBox::Yes == nRet);
54 QBuffer *buffer = new QBuffer();
55 buffer->setData(emptyData);
56 buffer->open(QIODevice::ReadOnly);
57 request->reply("text/html", buffer);
58}
59
60bool CSystemProtocolHandler::isUrlSafe(const QUrl &url) const
61{
62 // 安全检查:防止 file:// 等危险协议
63 QString scheme = url.scheme();
64 if (scheme == "file" || scheme == "data") {
65 if(url.isLocalFile()) {
66 QFileInfo fi(url.toLocalFile());
67 if(fi.suffix() == "rrc")
68 return true;
69 else
70 return false;
71 }
72 // 只允许特定路径
73 if (scheme == "file" && !url.path().startsWith("/tmp/")) {
74 return false;
75 }
76 return false;
77 }
78
79 // 检查是否包含可疑字符
80 QString urlStr = url.toString();
81 if (urlStr.contains("..") || urlStr.contains("%2e%2e")) {
82 return false;
83 }
84
85 return true;
86}
87
88QByteArray CSystemProtocolHandler::generateResponsePage(const QUrl &url, bool opened) const
89{
90 QString html = R"(
91 <html>
92 <head>
93 <meta charset="UTF-8">
94 <style>
95 body { font-family: Arial, sans-serif; margin: 50px; }
96 .success { color: #4CAF50; }
97 .error { color: #f44336; }
98 </style>
99 </head>
100 <body>
101 <h2>%1</h2>
102 <p>%2: %3</p>
103 <p>URL: %4</p>
104 <p class="%5">%6: %7</p>
105 <p><a href='javascript:history.back()'>%8</a></p>
106 </body>
107 </html>
108 )";
109
110 html = html.arg(tr("Process protocol"))
111 .arg(tr("Protocol"))
112 .arg(url.scheme())
113 .arg(url.toString().toHtmlEscaped())
114 .arg(opened ? "success" : "error")
115 .arg(tr("Status"))
116 .arg(opened ? tr("External application opened") : tr("Cancel Open"))
117 .arg(tr("Go back"));
118
119 return html.toUtf8();
120}