#include "slxbrowser.h" #include "webview.h" #include "nam.h" #include #include #include #include #include #include #include #include #include #include #include static QRegularExpression urlListToRegExp(const QStringList &list); SlxBrowser::SlxBrowser(BrowserSettings settings) : QMainWindow(nullptr), _settings(std::move(settings)), _unsupportedUri(false), _blockedSite(false), _lastPageLoad(0), _activity(false), _lastActivity(0), _pageValid(false) { _settings.reloadInterval *= 1000; if (_settings.zoom <= 0) { _settings.zoom = 100; } else if (_settings.zoom > 400) { _settings.zoom = 400; } if (_settings.fullscreen) { this->showFullScreen(); this->setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint); } else if (_settings.maximized) { this->showMaximized(); } // Enable local storage in WebEngine _browser = new WebView; _browser->page()->settings()->setAttribute(QWebEngineSettings::LocalStorageEnabled, true); _browser->setIgnoreSslErrors(_settings.ignoreSslErrors); auto *w = new QWidget; QLayout *l = new QVBoxLayout; _browser->setZoomFactor(float(_settings.zoom) * .01f); _progress = new QProgressBar; _progress->hide(); l->addWidget(_browser); l->addWidget(_progress); l->setMargin(0); l->setSpacing(0); l->setContentsMargins(0,0,0,0); w->setContentsMargins(0,0,0,0); w->setLayout(l); this->setCentralWidget(w); _reset.setSingleShot(true); connect(&_reset, &QTimer::timeout, this, &SlxBrowser::reloadInitial); connect(_browser, &WebView::loadStarted, this, &SlxBrowser::loadStarted); connect(_browser, &WebView::loadFinished, this, &SlxBrowser::loadFinished); connect(_browser, &WebView::loadProgress, this, &SlxBrowser::loadProgress); // URL filtering via interceptor if (!_settings.whiteList.isEmpty() || !_settings.blackList.isEmpty()) { if (_settings.blackList.isEmpty()) { _settings.blackList << "*"; } _settings.whiteList << _settings.url; // ensure initial URL allowed auto *interceptor = new SlxRequestInterceptor(urlListToRegExp(_settings.blackList), urlListToRegExp(_settings.whiteList), this); connect(interceptor, &SlxRequestInterceptor::urlBlocked, this, [this](const QUrl&){ _blockedSite = true; }); connect(interceptor, &SlxRequestInterceptor::unsupportedScheme, this, [this](const QUrl&){ _unsupportedUri = true; }); _browser->page()->profile()->setUrlRequestInterceptor(interceptor); } _browser->load(QUrl(_settings.url)); // _browser->show(); } SlxBrowser::~SlxBrowser() = default; void SlxBrowser::loadStarted() { _pageValid = false; _reset.stop(); if (_settings.reloadInterval > 0) { _reset.start(_settings.reloadInterval + 5000); } _progress->setValue(0); _progress->show(); } void SlxBrowser::maybeTriggerBack() { // Best-effort: if there is a back entry, go back if (_browser->page()->history()->canGoBack()) _browser->back(); } void SlxBrowser::loadFinished(bool ok) { _progress->hide(); bool abortedDl = _browser->wasAbortedDownload(); if (!abortedDl && !ok) { if (_unsupportedUri) { QMessageBox::warning(this, QString::fromUtf8("Denied"), QString::fromUtf8("This URL type is not supported.\n\n" "Diese Art Link wird nicht unterstützt.\n\n" "(z.B. Mail)")); } else if (_blockedSite) { maybeTriggerBack(); QTimer::singleShot(10, [this]() { QMessageBox::warning(this, QString::fromUtf8("Denied"), QString::fromUtf8("Target URL not allowed.\n\n" "Dieser Link führt auf eine nicht erlaubte Seite.")); }); } else { QString html = QString::fromUtf8( "

" "

Page Load Error

%1

" "

Back

" "
") .arg(QDateTime::currentDateTime().toString()); _browser->setHtml(html); _pageValid = false; if (_settings.reloadInterval > 0) { _reset.start(qMin(30000, _settings.reloadInterval)); } else { _reset.start(30000); } } } else { _pageValid = true; if (_settings.reloadInterval > 0) { _reset.start(qMax(_settings.reloadInterval / 20, 1000)); } } _unsupportedUri = false; _blockedSite = false; _lastPageLoad = QDateTime::currentMSecsSinceEpoch();; } void SlxBrowser::loadProgress(int progress) { _progress->setValue(progress); } void SlxBrowser::reloadInitial() { if (_pageValid) { if (_activity) { _lastActivity = QDateTime::currentMSecsSinceEpoch(); _activity = false; _reset.start(qMax(_settings.reloadInterval / 20, 1000)); return; } qint64 now = QDateTime::currentMSecsSinceEpoch(); if (now - qMax(_lastActivity, _lastPageLoad) > _settings.reloadInterval) { _browser->load(QUrl(_settings.url)); } else { _reset.start(qMax(_settings.reloadInterval / 20, 1000)); } } else { _browser->load(QUrl(_settings.url)); } } static QRegularExpression urlListToRegExp(const QStringList &list) { // 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; // 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('|') + ")$"); }