summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSimon Rettberg2025-09-22 14:18:00 +0200
committerSimon Rettberg2025-09-22 14:18:00 +0200
commitef6063ba3614b3f1a44179f82fbc0e9bdf47fe99 (patch)
tree290c7bf881e5c01ad818351e36ab5f87821ec766 /src
parentTry to get timeout logic under control (diff)
downloadslxgreeter-ef6063ba3614b3f1a44179f82fbc0e9bdf47fe99.tar.gz
slxgreeter-ef6063ba3614b3f1a44179f82fbc0e9bdf47fe99.tar.xz
slxgreeter-ef6063ba3614b3f1a44179f82fbc0e9bdf47fe99.zip
Port from QWebKit to QWebEngine
Port done by clion + GPT-5
Diffstat (limited to 'src')
-rw-r--r--src/global.cpp2
-rw-r--r--src/webview.cpp467
-rw-r--r--src/webview.h64
3 files changed, 336 insertions, 197 deletions
diff --git a/src/global.cpp b/src/global.cpp
index ce166c6..f20b4b5 100644
--- a/src/global.cpp
+++ b/src/global.cpp
@@ -148,7 +148,7 @@ QString Global::getCombinedIdpWhitelist()
QFileInfoList fileInfoList = configDir.entryInfoList(QStringList() << "*.idp", QDir::Files);
QSet<QString> list;
- for (QFileInfo fileInfo : fileInfoList) {
+ for (const QFileInfo& fileInfo : fileInfoList) {
QString filePath = fileInfo.absoluteFilePath();
QFile f(filePath);
if (!f.open(QFile::ReadOnly))
diff --git a/src/webview.cpp b/src/webview.cpp
index 745d700..1e4a3a4 100644
--- a/src/webview.cpp
+++ b/src/webview.cpp
@@ -1,196 +1,221 @@
#include "webview.h"
-#include "nam.h"
+
#include "global.h"
-#include <QWebFrame>
-#include <QNetworkReply>
+#include <QAction>
#include <QMessageBox>
#include <QTimer>
#include <QUrlQuery>
#include <QCryptographicHash>
#include <QCursor>
-#include <QWebHistory>
-#include <QNetworkCookieJar>
-#include <QWebElement>
#include <QRegularExpression>
-#include <QWebPage>
-#include <QWebFrame>
+#include <QDateTime>
+#include <QDebug>
+#include <QMenu>
+#include <QContextMenuEvent>
-static QRegularExpression urlListToRegExp(const QStringList &list);
+#include <QWebEngineHistory>
+#include <QWebEngineSettings>
+#include <QWebEngineProfile>
+#include <QWebEngineCookieStore>
+#include <QWebEngineDownloadItem>
+#include <QWebEngineUrlRequestInterceptor>
+#include <QWebEngineScriptCollection>
-// Override user-agent to make it appear mobile
-class UaWebPage : public QWebPage
+// Add: custom page to catch console messages from JS
+class ActivityPage : public QWebEnginePage
{
public:
- static QRegularExpression re;
+ explicit ActivityPage(QWebEngineProfile *profile, QObject *parent, std::function<void()> onActivity)
+ : QWebEnginePage(profile, parent), _onActivity(std::move(onActivity)) {}
- QString userAgentForUrl(const QUrl &url) const override {
- return QWebPage::userAgentForUrl(url).replace(re, "Mobile \\1");
+protected:
+ void javaScriptConsoleMessage(JavaScriptConsoleMessageLevel level,
+ const QString &message, int lineNumber,
+ const QString &sourceID) override
+ {
+ Q_UNUSED(level);
+ Q_UNUSED(lineNumber);
+ Q_UNUSED(sourceID);
+ // Recognize our activity marker
+ if (message == QLatin1String("LOG_USER_ACTIVITY")) {
+ qDebug() << "User activity detected";
+ if (_onActivity) _onActivity();
+ }
+ // fall through to default behavior
+ QWebEnginePage::javaScriptConsoleMessage(level, message, lineNumber, sourceID);
}
+
+private:
+ std::function<void()> _onActivity;
};
-QRegularExpression UaWebPage::re("(\\S+)$");
+static QRegularExpression urlListToRegExp(const QStringList &list);
-WebView::WebView(QWidget* parent)
- : QWebView(parent),
- _timerAbortMessage(new QTimer(this)),
- _abortedDownload(false),
- _inErrorState(false),
- _timerReset(new QTimer(this)),
- _firstLoad(false)
-{
- auto p = new UaWebPage;
- if (!Global::getCombinedIdpWhitelist().trimmed().isEmpty()) {
- QObject::connect(p, &UaWebPage::frameCreated, [this](QWebFrame *frame) {
- QObject::connect(frame, &QWebFrame::javaScriptWindowObjectCleared, [this, frame]() {
- this->jsInjector(frame);
- });
- });
- }
- this->setPage(p);
- _timerAbortMessage->setSingleShot(true);
- _timerReset->setSingleShot(true);
- connect(page(), SIGNAL(windowCloseRequested()), this, SLOT(windowCloseRequested()));
- auto bl = Global::urlBlacklist();
- auto wl = Global::urlWhitelist();
- page()->setNetworkAccessManager(new SlxNetworkAccessManager(urlListToRegExp(bl),
- urlListToRegExp(wl), this));
- page()->setForwardUnsupportedContent(true);
- page()->settings()->setAttribute(QWebSettings::LocalStorageEnabled, true);
- //page()->settings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, true);
- connect(page(), SIGNAL(unsupportedContent(QNetworkReply*)),this,SLOT(unsupportedContent(QNetworkReply*)));
- connect(page(), SIGNAL(downloadRequested(QNetworkRequest)),this,SLOT(downloadRequest(QNetworkRequest)));
- connect(_timerAbortMessage, &QTimer::timeout, this, &WebView::downloadDeniedMessage);
- connect(_timerReset, &QTimer::timeout, this, [this]() {
- this->resetBrowserAndTimeout();
- emit triggerReset(tr("Inactivity Timeout"));
- });
- connect(this, &QWebView::loadFinished, this, &WebView::onLoadFinished);
-}
+// URL interceptor for black-/whitelist
+class SlxUrlRequestInterceptor : public QWebEngineUrlRequestInterceptor
+{
+public:
+ SlxUrlRequestInterceptor(const QRegularExpression& blackList, const QRegularExpression& whiteList)
+ : _black(blackList), _white(whiteList) {}
-void WebView::resetBrowserAndTimeout()
+ void interceptRequest(QWebEngineUrlRequestInfo &info) override {
+ const QString u = info.requestUrl().toString();
+ if (_white.isValid() && !_white.match(u).hasMatch()) {
+ info.block(true);
+ return;
+ }
+ if (_black.isValid() && _black.match(u).hasMatch()) {
+ info.block(true);
+ return;
+ }
+ }
+private:
+ QRegularExpression _black, _white;
+};
+
+WebView::WebView(QWidget* parent)
+ : QWebEngineView(parent),
+ _timerAbortMessage(new QTimer(this)),
+ _abortedDownload(false),
+ _inErrorState(false),
+ _timerReset(new QTimer(this)),
+ _firstLoad(false),
+ _profile(new QWebEngineProfile(this))
{
- _timerReset->stop();
- _timerAbortMessage->stop();
- this->stop();
- this->page()->mainFrame()->setContent("");
+ // Configure profile, no persistent cookies or cache
+ _profile->setPersistentCookiesPolicy(QWebEngineProfile::NoPersistentCookies);
+ _profile->setHttpCacheType(QWebEngineProfile::MemoryHttpCache);
+
+ {
+ // Make sure we get mobile pages if applicable, since the window is rather small
+ QString ua = _profile->httpUserAgent();
+ ua.replace(QRegularExpression("(\\S+)$"), "Mobile \\1");
+ _profile->setHttpUserAgent(ua);
+ }
+
+ {
+ // Any url filtering, since many pages allow you to escape through different links
+ auto bl = Global::urlBlacklist();
+ auto wl = Global::urlWhitelist();
+ _profile->setRequestInterceptor(new SlxUrlRequestInterceptor(urlListToRegExp(bl), urlListToRegExp(wl)));
+ }
+
+ // Use our custom page to receive activity signals from injected JS
+ auto *p = new ActivityPage(_profile, this, [this]() {
+ this->resetTimeout();
+ });
+ setPage(p);
+
+ // Settings
+ page()->settings()->setAttribute(QWebEngineSettings::LocalStorageEnabled, true);
+
+ // Also reset on scrolls (native signal)
+ connect(page(), &QWebEnginePage::scrollPositionChanged, this, [this](const QPointF &) {
+ this->resetTimeout();
+ });
+
+ // Block downloads
+ connect(_profile, &QWebEngineProfile::downloadRequested, this, [this](QWebEngineDownloadItem *item) {
+ Q_UNUSED(item);
+ _abortedDownload = true;
+ _timerAbortMessage->start(1);
+ item->cancel();
+ });
+
+ // Handle window close requests, simulate back navigation
+ connect(page(), &QWebEnginePage::windowCloseRequested, this, &WebView::windowCloseRequested);
+
+ _timerAbortMessage->setSingleShot(true);
+ _timerReset->setSingleShot(true);
+
+ connect(_timerAbortMessage, &QTimer::timeout, this, &WebView::downloadDeniedMessage);
+ connect(_timerReset, &QTimer::timeout, this, [this]() {
+ this->resetBrowserAndTimeout();
+ emit triggerReset(tr("Inactivity Timeout"));
+ });
+ connect(this, &QWebEngineView::loadFinished, this, &WebView::onLoadFinished);
+
+ // JS-Injection
+ installJsInjectionScript();
}
-void WebView::jsInjector(QWebFrame *frame)
+void WebView::resetBrowserAndTimeout()
{
- QString str = Global::getCombinedIdpWhitelist().replace(
- QRegularExpression("[^\\w. /:-]", QRegularExpression::UseUnicodePropertiesOption),
- QStringLiteral(""));
- frame->evaluateJavaScript(QStringLiteral("var slxIdpFilter ='") + str + QStringLiteral("'"));
+ _timerReset->stop();
+ _timerAbortMessage->stop();
+ this->stop();
+ this->setHtml(QString());
}
void WebView::windowCloseRequested()
{
- // If we have an old URL stored on the stack, navigate back to it, otherwise we return and nothing happens
- if (_urls.empty())
- return;
- QUrl url = _urls.pop();
- page()->mainFrame()->load(url);
+ if (_urls.empty())
+ return;
+ const QUrl url = _urls.pop();
+ this->setUrl(url);
}
-QWebView* WebView::createWindow(QWebPage::WebWindowType)
+QWebEngineView* WebView::createWindow(QWebEnginePage::WebWindowType)
{
- // Remember current URL, then return the current Web View so no new window opens
- _urls.push(this->url());
- return this;
+ // Open in same window and push old URL to stack, so we can navigate back on close requests
+ _urls.push(this->url());
+ return this;
}
void WebView::mousePressEvent(QMouseEvent* ev)
{
- QWebView::mousePressEvent(ev);
- resetTimeout();
+ QWebEngineView::mousePressEvent(ev);
+ resetTimeout();
}
void WebView::keyPressEvent(QKeyEvent* ev)
{
- QWebView::keyPressEvent(ev);
- resetTimeout();
+ QWebEngineView::keyPressEvent(ev);
+ resetTimeout();
}
void WebView::wheelEvent(QWheelEvent* ev)
{
- QWebView::wheelEvent(ev);
- resetTimeout();
+ QWebEngineView::wheelEvent(ev);
+ resetTimeout();
}
-void WebView::resetTimeout()
+void WebView::resetTimeout() const
{
- if (!_inErrorState) {
- _timerReset->start(60000);
- }
-}
-
-void WebView::unsupportedContent(QNetworkReply* rep)
-{
- _abortedDownload = true;
- rep->abort();
- rep->deleteLater();
- _timerAbortMessage->start(1);
-}
-
-void WebView::downloadRequest(QNetworkRequest)
-{
- _timerAbortMessage->start(1);
+ if (!_inErrorState) {
+ _timerReset->start(60000);
+ }
}
void WebView::downloadDeniedMessage()
{
- QMessageBox::warning(this->parentWidget(), QString::fromUtf8("Denied"),
- QString::fromUtf8("The requested action triggered a download, which is not allowed.\n\n"
- "Diese Aktion löst einen Download aus, was nicht erlaubt ist."));
+ QMessageBox::warning(this->parentWidget(), QString::fromUtf8("Denied"),
+ QString::fromUtf8("The requested action triggered a download, which is not allowed.\n\n"
+ "Diese Aktion löst einen Download aus, was nicht erlaubt ist."));
}
void WebView::onLoadFinished(bool ok)
{
- if (_abortedDownload || !ok) {
- _abortedDownload = false;
- _inErrorState = true;
- _timerReset->start(10000);
- return;
- }
- _inErrorState = false;
- auto user = this->page()->mainFrame()->documentElement().findFirst("#bwlp-username");
- auto pass = this->page()->mainFrame()->documentElement().findFirst("#bwlp-password");
- auto err = this->page()->mainFrame()->documentElement().findFirst("#bwlp-error");
- auto hash = this->page()->mainFrame()->documentElement().findFirst("#bwlp-hash");
- auto adminToken = this->page()->mainFrame()->documentElement().findFirst("#bwlp-cow-token");
- if (!user.isNull() && !pass.isNull() && !hash.isNull()) {
- if (hash.toPlainText() != QCryptographicHash::hash(_token.toLatin1(), QCryptographicHash::Md5).toHex()) {
- qDebug() << " *** Invalid security hash ***";
- emit triggerReset("Invalid Hash");
- return;
- }
- auto ustr = user.toPlainText();
- auto upass = pass.toPlainText();
- if (Global::isValidShibCreds(ustr, upass)) {
- QString token = adminToken.toPlainText();
- if (!token.isEmpty()) {
- Global::writeCowToken(ustr, token);
- }
- emit startAuthentication(ustr, "shib=" + _token + upass);
- } else {
- emit triggerReset("Invalid user or passhash format");
- }
- } else if (!err.isNull()) {
- this->stop();
- this->page()->mainFrame()->setContent("");
- emit triggerReset(err.toPlainText());
- } else {
- _timerReset->start(60000);
- }
- if (_firstLoad) {
- _firstLoad = false;
- this->page()->history()->clear();
- this->history()->clear();
- }
+ if (_abortedDownload || !ok) {
+ _abortedDownload = false;
+ _inErrorState = true;
+ _timerReset->start(10000);
+ return;
+ }
+ _inErrorState = false;
+
+ // Check if this is the result of the auth process
+ evaluateAuthDom();
+
+ if (_firstLoad) {
+ _firstLoad = false;
+ if (this->history())
+ this->history()->clear();
+ }
}
-void WebView::reset(const QString baseUrl)
+void WebView::reset(const QString& baseUrl)
{
QUrl url(baseUrl);
QUrlQuery q(url.query());
@@ -203,7 +228,11 @@ void WebView::reset(const QString baseUrl)
q.addQueryItem("token", _token);
url.setQuery(q);
_urls.clear();
- this->page()->networkAccessManager()->setCookieJar(new QNetworkCookieJar);
+
+ // Clear all cookies
+ if (_profile && _profile->cookieStore())
+ _profile->cookieStore()->deleteAllCookies();
+
this->setUrl(url);
_firstLoad = true;
_timerAbortMessage->stop();
@@ -212,33 +241,135 @@ void WebView::reset(const QString baseUrl)
static QRegularExpression urlListToRegExp(const QStringList &list)
{
- if (list.isEmpty())
- return QRegularExpression("(["); // Return an invalid regex, we use .isValid to check if the list is to be used
- // We search in the escaped string, so actually look for \*\* and \*
- // Capture char before that because it must not be another backslash, as that
- // means the star was already escaped in the list.
- // Since these are C strings there are some additional backslashes here.
- static const QRegularExpression STARSTAR("(^|[^\\\\])\\\\\\*\\\\\\*");
- static const QRegularExpression STAR("(^|[^\\\\])\\\\\\*");
- static const QRegularExpression QUEST("(^|[^\\\\])\\\\\\?");
- static const QString STARSTAR_REP("\\1.*");
- static const QString STAR_REP("\\1[^/]*");
- static const QString QUEST_REP("\\1.?");
- QStringList regexes; // All my regex's live in Regtexas
- for (const QString &str : list) {
- QString mangled;
- if (str.contains(QLatin1String("//"))) {
- mangled = str;
- } else if (str.contains(QLatin1Char('/')) || str.contains(QLatin1String("**"))) {
- mangled = "*//" + str;
- } else {
- mangled = "*//" + str + "/**";
- }
- mangled = QRegularExpression::escape(mangled);
- mangled = mangled.replace(STARSTAR, STARSTAR_REP).replace(STAR, STAR_REP)
- .replace(QUEST, QUEST_REP);
- regexes << mangled;
- }
- qDebug() << regexes;
- return QRegularExpression("^(" + regexes.join('|') + ")$");
+ if (list.isEmpty())
+ return QRegularExpression("(["); // Return an invalid regex, we use .isValid to check if the list is to be used.
+ // We search in the escaped string, so actually look for \*\* and \*
+ // Capture char before that because it must not be another backslash, as that
+ // means the star was already escaped in the list.
+ static const QRegularExpression STARSTAR(R"((^|[^\\])\\\*\\\*)");
+ static const QRegularExpression STAR(R"((^|[^\\])\\\*)");
+ static const QRegularExpression QUEST(R"((^|[^\\])\\\?)");
+ static const QString STARSTAR_REP("\\1.*");
+ static const QString STAR_REP("\\1[^/]*");
+ static const QString QUEST_REP("\\1.?");
+ QStringList regexes;
+ for (const QString &str : list) {
+ QString mangled;
+ if (str.contains(QLatin1String("//"))) {
+ mangled = str;
+ } else if (str.contains(QLatin1Char('/')) || str.contains(QLatin1String("**"))) {
+ mangled = "*//" + str;
+ } else {
+ mangled = "*//" + str + "/**";
+ }
+ mangled = QRegularExpression::escape(mangled);
+ mangled = mangled.replace(STARSTAR, STARSTAR_REP).replace(STAR, STAR_REP)
+ .replace(QUEST, QUEST_REP);
+ regexes << mangled;
+ }
+ qDebug() << regexes;
+ return QRegularExpression("^(" + regexes.join('|') + ")$");
+}
+
+void WebView::installJsInjectionScript()
+{
+ // If we should filter the list of allowed IdPs, inject the list into
+ // the page as JavaScript
+ QString str = Global::getCombinedIdpWhitelist().replace(
+ QRegularExpression("[^\\w. /:-]", QRegularExpression::UseUnicodePropertiesOption),
+ QString());
+ QWebEngineScript script;
+ script.setName(QStringLiteral("slxIdpFilterInjector"));
+ script.setInjectionPoint(QWebEngineScript::DocumentCreation);
+ script.setWorldId(QWebEngineScript::MainWorld);
+ script.setRunsOnSubFrames(true);
+ script.setSourceCode(QStringLiteral("var slxIdpFilter ='") + str + QStringLiteral("';"));
+ page()->scripts().insert(script);
+
+ // Inject activity listeners to signal user interaction back to C++
+ QWebEngineScript activityScript;
+ activityScript.setName(QStringLiteral("slxUserActivity"));
+ activityScript.setInjectionPoint(QWebEngineScript::DocumentCreation);
+ activityScript.setWorldId(QWebEngineScript::MainWorld);
+ activityScript.setRunsOnSubFrames(true);
+ activityScript.setSourceCode(QStringLiteral(
+ "(function(){\n"
+ " var last=0; function ping(){\n"
+ " var now=Date.now(); if(now-last<2000) return; last=now;\n"
+ " try{console.debug('LOG_USER_ACTIVITY');}catch(e){}\n"
+ " }\n"
+ " var evts=['mousedown','mouseup','click','keydown','keyup','wheel','touchstart','touchend','scroll'];\n"
+ " evts.forEach(function(ev){\n"
+ " window.addEventListener(ev, ping, {passive:true, capture:true});\n"
+ " });\n"
+ "})();\n"
+ ));
+ page()->scripts().insert(activityScript);
+}
+
+void WebView::contextMenuEvent(QContextMenuEvent* ev)
+{
+ // Build the default menu
+ QMenu* menu = page()->createStandardContextMenu();
+
+ // Find and remove/hide the "View source" action
+ QAction* viewSource = page()->action(QWebEnginePage::ViewSource);
+ if (viewSource) {
+ viewSource->setVisible(false); // or: menu->removeAction(viewSource);
+ viewSource->setEnabled(false);
+ }
+
+ // Show the customized menu
+ menu->exec(ev->globalPos());
+ menu->deleteLater();
+ ev->accept();
+}
+
+void WebView::evaluateAuthDom()
+{
+ // See if expected auth fields are in the document. If so, we want to trigger the
+ // authentication process using those fields.
+ const QString js = QStringLiteral(
+ "(function(){"
+ " function t(sel){var e=document.querySelector(sel);return e?e.textContent:'';}"
+ " return {"
+ " user: t('#bwlp-username'),"
+ " pass: t('#bwlp-password'),"
+ " err: t('#bwlp-error'),"
+ " hash: t('#bwlp-hash'),"
+ " adminToken: t('#bwlp-cow-token')"
+ " };"
+ "})();"
+ );
+
+ page()->runJavaScript(js, [this](const QVariant &v){
+ const auto map = v.toMap();
+ const QString user = map.value(QStringLiteral("user")).toString().trimmed();
+ const QString pass = map.value(QStringLiteral("pass")).toString();
+ const QString err = map.value(QStringLiteral("err")).toString();
+ const QString hash = map.value(QStringLiteral("hash")).toString();
+ const QString adminToken = map.value(QStringLiteral("adminToken")).toString();
+
+ if (!user.isEmpty() && !pass.isEmpty() && !hash.isEmpty()) {
+ if (hash != QCryptographicHash::hash(_token.toLatin1(), QCryptographicHash::Md5).toHex()) {
+ qDebug() << " *** Invalid security hash ***";
+ emit triggerReset(QStringLiteral("Invalid Hash"));
+ return;
+ }
+ if (Global::isValidShibCreds(user, pass)) {
+ if (!adminToken.isEmpty()) {
+ Global::writeCowToken(user, adminToken);
+ }
+ emit startAuthentication(user, QStringLiteral("shib=") + _token + pass);
+ } else {
+ emit triggerReset(QStringLiteral("Invalid user or passhash format"));
+ }
+ } else if (!err.isEmpty()) {
+ this->stop();
+ this->setHtml(QString());
+ emit triggerReset(err);
+ } else {
+ _timerReset->start(60000);
+ }
+ });
}
diff --git a/src/webview.h b/src/webview.h
index 48c0ceb..71d9e87 100644
--- a/src/webview.h
+++ b/src/webview.h
@@ -2,55 +2,63 @@
#define WEBVIEW_H_
#include <QStack>
-#include <QWebView>
#include <QNetworkRequest>
+#include <QRegularExpression>
+
+#include <QWebEngineView>
+#include <QWebEnginePage>
+#include <QWebEngineProfile>
+#include <QWebEngineScript>
-class QNetworkReply;
class QTimer;
-class QWebFrame;
/**
* Make sure pages that want to load in a new tab are actually loaded in the same page,
* and remember the previous URL in case the "new tab" requests to be closed.
*/
-class WebView : public QWebView
+class WebView : public QWebEngineView
{
Q_OBJECT
public:
- WebView(QWidget* parent = NULL);
- void reset(const QString baseUrl);
+ explicit WebView(QWidget* parent = nullptr);
+ void reset(const QString& baseUrl);
- void resetBrowserAndTimeout();
+ void resetBrowserAndTimeout();
protected:
- QWebView *createWindow(QWebPage::WebWindowType) override;
- void mousePressEvent(QMouseEvent*) override;
- void keyPressEvent(QKeyEvent*) override;
- void wheelEvent(QWheelEvent*) override;
-
- void resetTimeout();
+ QWebEngineView *createWindow(QWebEnginePage::WebWindowType) override;
+ void mousePressEvent(QMouseEvent*) override;
+ void keyPressEvent(QKeyEvent*) override;
+ void wheelEvent(QWheelEvent*) override;
- void jsInjector(QWebFrame *frame);
+ void resetTimeout() const;
signals:
- void triggerReset(const QString &message);
- void startAuthentication(const QString &user, const QString &pass);
+ void triggerReset(const QString &message);
+ void startAuthentication(const QString &user, const QString &pass);
protected slots:
- void windowCloseRequested();
- void unsupportedContent(QNetworkReply*);
- void downloadRequest(QNetworkRequest);
- void downloadDeniedMessage();
- void onLoadFinished(bool ok);
+ void windowCloseRequested();
+ void downloadDeniedMessage();
+ void onLoadFinished(bool ok);
private:
- QStack<QUrl> _urls;
- QTimer *_timerAbortMessage;
- bool _abortedDownload;
- bool _inErrorState;
- QString _token;
- QTimer *_timerReset;
- bool _firstLoad;
+ void installJsInjectionScript();
+
+void contextMenuEvent(QContextMenuEvent *ev);
+
+void evaluateAuthDom();
+
+private:
+ QStack<QUrl> _urls;
+ QTimer *_timerAbortMessage;
+ bool _abortedDownload;
+ bool _inErrorState;
+ QString _token;
+ QTimer *_timerReset;
+ bool _firstLoad;
+
+ QWebEngineProfile *_profile;
};
#endif