226 lines
7.1 KiB
C++
226 lines
7.1 KiB
C++
#include "webview.h"
|
|
|
|
#include <QWebEnginePage>
|
|
#include <QWebEngineProfile>
|
|
#include <QWebEngineUrlRequestInterceptor>
|
|
#include <QWebEngineUrlRequestJob>
|
|
#include <QWebEngineUrlSchemeHandler>
|
|
#include <QWebEngineView>
|
|
#include <QDesktopServices>
|
|
#include <QProgressBar>
|
|
#include <QLoggingCategory>
|
|
#include <QLocale>
|
|
#include <QWebEngineCertificateError>
|
|
#include <QMessageBox>
|
|
|
|
#include "common/utility.h"
|
|
|
|
namespace OCC {
|
|
|
|
Q_LOGGING_CATEGORY(lcWizardWebiew, "gui.wizard.webview", QtInfoMsg)
|
|
|
|
|
|
class WebViewPageUrlRequestInterceptor : public QWebEngineUrlRequestInterceptor
|
|
{
|
|
Q_OBJECT
|
|
public:
|
|
WebViewPageUrlRequestInterceptor(QObject *parent = nullptr);
|
|
void interceptRequest(QWebEngineUrlRequestInfo &info) override;
|
|
};
|
|
|
|
class WebViewPageUrlSchemeHandler : public QWebEngineUrlSchemeHandler
|
|
{
|
|
Q_OBJECT
|
|
public:
|
|
WebViewPageUrlSchemeHandler(QObject *parent = nullptr);
|
|
void requestStarted(QWebEngineUrlRequestJob *request) override;
|
|
|
|
Q_SIGNALS:
|
|
void urlCatched(QString user, QString pass, QString host);
|
|
};
|
|
|
|
class WebEnginePage : public QWebEnginePage {
|
|
public:
|
|
WebEnginePage(QWebEngineProfile *profile, QObject* parent = nullptr);
|
|
QWebEnginePage * createWindow(QWebEnginePage::WebWindowType type) override;
|
|
void setUrl(const QUrl &url);
|
|
|
|
protected:
|
|
bool certificateError(const QWebEngineCertificateError &certificateError) override;
|
|
|
|
private:
|
|
QUrl _rootUrl;
|
|
};
|
|
|
|
// We need a separate class here, since we cannot simply return the same WebEnginePage object
|
|
// this leads to a strage segfault somewhere deep inside of the QWebEngine code
|
|
class ExternalWebEnginePage : public QWebEnginePage {
|
|
public:
|
|
ExternalWebEnginePage(QWebEngineProfile *profile, QObject* parent = nullptr);
|
|
bool acceptNavigationRequest(const QUrl &url, QWebEnginePage::NavigationType type, bool isMainFrame) override;
|
|
};
|
|
|
|
WebView::WebView(QWidget *parent)
|
|
: QWidget(parent),
|
|
_ui()
|
|
{
|
|
_ui.setupUi(this);
|
|
|
|
_webview = new QWebEngineView(this);
|
|
_profile = new QWebEngineProfile(this);
|
|
_page = new WebEnginePage(_profile);
|
|
_interceptor = new WebViewPageUrlRequestInterceptor(this);
|
|
_schemeHandler = new WebViewPageUrlSchemeHandler(this);
|
|
|
|
const QString userAgent(Utility::userAgentString());
|
|
_profile->setHttpUserAgent(userAgent);
|
|
QWebEngineProfile::defaultProfile()->setHttpUserAgent(userAgent);
|
|
_profile->setRequestInterceptor(_interceptor);
|
|
_profile->installUrlSchemeHandler("nc", _schemeHandler);
|
|
|
|
/*
|
|
* Set a proper accept langauge to the language of the client
|
|
* code from: http://code.qt.io/cgit/qt/qtbase.git/tree/src/network/access/qhttpnetworkconnection.cpp
|
|
*/
|
|
{
|
|
QString systemLocale = QLocale::system().name().replace(QChar::fromLatin1('_'),QChar::fromLatin1('-'));
|
|
QString acceptLanguage;
|
|
if (systemLocale == QLatin1String("C")) {
|
|
acceptLanguage = QString::fromLatin1("en,*");
|
|
} else if (systemLocale.startsWith(QLatin1String("en-"))) {
|
|
acceptLanguage = systemLocale + QLatin1String(",*");
|
|
} else {
|
|
acceptLanguage = systemLocale + QLatin1String(",en,*");
|
|
}
|
|
_profile->setHttpAcceptLanguage(acceptLanguage);
|
|
}
|
|
|
|
_webview->setPage(_page);
|
|
_ui.verticalLayout->addWidget(_webview);
|
|
|
|
connect(_webview, &QWebEngineView::loadProgress, _ui.progressBar, &QProgressBar::setValue);
|
|
connect(_schemeHandler, &WebViewPageUrlSchemeHandler::urlCatched, this, &WebView::urlCatched);
|
|
}
|
|
|
|
void WebView::setUrl(const QUrl &url) {
|
|
_page->setUrl(url);
|
|
}
|
|
|
|
WebView::~WebView() {
|
|
/*
|
|
* The Qt implmentation deletes children in the order they are added to the
|
|
* object tree, so in this case _page is deleted after _profile, which
|
|
* violates the assumption that _profile should exist longer than
|
|
* _page [1]. Here I delete _page manually so that _profile can be safely
|
|
* deleted later.
|
|
*
|
|
* [1] https://doc.qt.io/qt-5/qwebenginepage.html#QWebEnginePage-1
|
|
*/
|
|
delete _page;
|
|
}
|
|
|
|
WebViewPageUrlRequestInterceptor::WebViewPageUrlRequestInterceptor(QObject *parent)
|
|
: QWebEngineUrlRequestInterceptor(parent) {
|
|
|
|
}
|
|
|
|
void WebViewPageUrlRequestInterceptor::interceptRequest(QWebEngineUrlRequestInfo &info) {
|
|
info.setHttpHeader("OCS-APIREQUEST", "true");
|
|
}
|
|
|
|
WebViewPageUrlSchemeHandler::WebViewPageUrlSchemeHandler(QObject *parent)
|
|
: QWebEngineUrlSchemeHandler(parent) {
|
|
|
|
}
|
|
|
|
void WebViewPageUrlSchemeHandler::requestStarted(QWebEngineUrlRequestJob *request) {
|
|
QUrl url = request->requestUrl();
|
|
|
|
QString path = url.path(0).mid(1); // get undecoded path
|
|
QStringList parts = path.split("&");
|
|
|
|
QString server;
|
|
QString user;
|
|
QString password;
|
|
|
|
for (QString part : parts) {
|
|
if (part.startsWith("server:")) {
|
|
server = part.mid(7);
|
|
} else if (part.startsWith("user:")) {
|
|
user = part.mid(5);
|
|
} else if (part.startsWith("password:")) {
|
|
password = part.mid(9);
|
|
}
|
|
}
|
|
|
|
qCDebug(lcWizardWebiew()) << "Got raw user from request path: " << user;
|
|
|
|
user = user.replace(QChar('+'), QChar(' '));
|
|
password = password.replace(QChar('+'), QChar(' '));
|
|
|
|
user = QUrl::fromPercentEncoding(user.toUtf8());
|
|
password = QUrl::fromPercentEncoding(password.toUtf8());
|
|
|
|
if (!server.startsWith("http://") && !server.startsWith("https://")) {
|
|
server = "https://" + server;
|
|
}
|
|
qCInfo(lcWizardWebiew()) << "Got user: " << user << ", server: " << server;
|
|
|
|
emit urlCatched(user, password, server);
|
|
}
|
|
|
|
|
|
WebEnginePage::WebEnginePage(QWebEngineProfile *profile, QObject* parent) : QWebEnginePage(profile, parent) {
|
|
|
|
}
|
|
|
|
QWebEnginePage * WebEnginePage::createWindow(QWebEnginePage::WebWindowType type) {
|
|
ExternalWebEnginePage *view = new ExternalWebEnginePage(this->profile());
|
|
return view;
|
|
}
|
|
|
|
void WebEnginePage::setUrl(const QUrl &url) {
|
|
QWebEnginePage::setUrl(url);
|
|
_rootUrl = url;
|
|
}
|
|
|
|
bool WebEnginePage::certificateError(const QWebEngineCertificateError &certificateError) {
|
|
if (certificateError.error() == QWebEngineCertificateError::CertificateAuthorityInvalid &&
|
|
certificateError.url().host() == _rootUrl.host()) {
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* TODO properly improve this.
|
|
* The certificate should be displayed.
|
|
*
|
|
* Or rather we should do a request with the QNAM and see if it works (then it is in the store).
|
|
* This is just a quick fix for now.
|
|
*/
|
|
QMessageBox messageBox;
|
|
messageBox.setText(tr("Invalid certificate detected"));
|
|
messageBox.setInformativeText(tr("The host \"%1\" provided an invalid certificate. Continue?").arg(certificateError.url().host()));
|
|
messageBox.setIcon(QMessageBox::Warning);
|
|
messageBox.setStandardButtons(QMessageBox::Yes|QMessageBox::No);
|
|
messageBox.setDefaultButton(QMessageBox::No);
|
|
|
|
int ret = messageBox.exec();
|
|
|
|
return ret == QMessageBox::Yes;
|
|
}
|
|
|
|
ExternalWebEnginePage::ExternalWebEnginePage(QWebEngineProfile *profile, QObject* parent) : QWebEnginePage(profile, parent) {
|
|
|
|
}
|
|
|
|
|
|
bool ExternalWebEnginePage::acceptNavigationRequest(const QUrl &url, QWebEnginePage::NavigationType type, bool isMainFrame)
|
|
{
|
|
QDesktopServices::openUrl(url);
|
|
return false;
|
|
}
|
|
|
|
}
|
|
|
|
#include "webview.moc"
|