#include "webview.h" #include #include #include #include #include #include #include #include #include #include #include #include // Override user-agent to make it appear mobile class UaWebPage : public QWebPage { public: static QRegularExpression re; QString userAgentForUrl(const QUrl &url) const override { return QWebPage::userAgentForUrl(url).replace(re, "Mobile \\1"); } }; QRegularExpression UaWebPage::re("(\\S+)$"); WebView::WebView(QWidget* parent) : QWebView(parent), _timerAbortMessage(new QTimer(this)), _abortedDownload(false), _inErrorState(false), _timerReset(new QTimer(this)) { this->setPage(new UaWebPage); _timerAbortMessage->setSingleShot(true); _timerReset->setSingleShot(true); connect(page(), SIGNAL(windowCloseRequested()), this, SLOT(windowCloseRequested())); page()->setForwardUnsupportedContent(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]() { emit triggerReset(tr("Inactivity Timeout")); this->stop(); this->page()->mainFrame()->setContent(""); }); connect(this, &QWebView::loadFinished, this, &WebView::onLoadFinished); } 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); } QWebView* WebView::createWindow(QWebPage::WebWindowType) { // Remember current URL, then return the current Web View so no new window opens _urls.push(this->url()); return this; } void WebView::mousePressEvent(QMouseEvent* ev) { QWebView::mousePressEvent(ev); resetTimeout(); } void WebView::keyPressEvent(QKeyEvent* ev) { QWebView::keyPressEvent(ev); resetTimeout(); } void WebView::wheelEvent(QWheelEvent* ev) { QWebView::wheelEvent(ev); resetTimeout(); } void WebView::resetTimeout() { 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); } 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.")); } 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"); if (!user.isNull() && !pass.isNull()) { emit startAuthentication(user.toPlainText(), "shib=" + _token + pass.toPlainText()); } else if (!err.isNull()) { emit triggerReset(err.toPlainText()); this->stop(); this->page()->mainFrame()->setContent(""); } else { _timerReset->start(60000); } } void WebView::reset(const QString baseUrl) { QUrl url(baseUrl); QUrlQuery q(url.query()); q.addQueryItem("action", "browser"); QByteArray input; input.append((const char*)this, sizeof(*this)); input.append(QString().sprintf("%d %d", QCursor::pos().x(), QCursor::pos().y())); input.append(QString::number(QDateTime::currentMSecsSinceEpoch())); _token = QCryptographicHash::hash(input, QCryptographicHash::Md5).chopped(8).toHex(); q.addQueryItem("token", _token); url.setQuery(q); _urls.clear(); this->page()->networkAccessManager()->setCookieJar(new QNetworkCookieJar); this->history()->clear(); this->setUrl(url); _timerAbortMessage->stop(); _timerReset->stop(); }