From a3b230d0a938925421ae90aeca316c5b787fd47b Mon Sep 17 00:00:00 2001 From: Iva Horn Date: Mon, 1 Jun 2026 14:53:33 +0200 Subject: [PATCH] chore: Remove QtWebEngine Drop the legacy embedded login flow (Flow v1 / WebViewFlow) and every piece of build, packaging, and signing infrastructure that existed to support it. The modern OAuth flow (Flow2, used by Nextcloud server >= 16.0.0) already drives login through the system browser and remains the only authentication path. User-visible consequence: Nextcloud servers older than 16.0.0, and any server advertising the legacy globalscale.desktoplogin=1 capability, can no longer be added through an in-app embedded browser. Modern servers are unaffected. Changes: - delete src/gui/wizard/webview{,page}.{h,cpp,ui,ui.license} - drop BUILD_WITH_WEBENGINE option, find_package calls, and target_link_libraries entries from CMake; drop the cmakedefine in config.h.in - remove DetermineAuthTypeJob's WebViewFlow enum value and the third (OldFlow) capability probe; the job now only runs the GET and PROPFIND probes - remove ConfigFile::forceLoginV2 / setForceLoginV2 and the forceLoginV2 settings key - drop the useFlow2 boolean machinery: WebFlowCredentialsDialog now always hosts Flow2AuthWidget, and OwncloudWizard / OwncloudSetupPage no longer thread a useFlow2 flag - drop Page_WebView, WebViewPage, the welcomepage WebEngine branch (Create Account now always opens the system browser), and related #ifdef WITH_WEBENGINE blocks - remove --without-webengine flag and buildWithWebEngine craft option from mac-crafter - remove signQtWebEngineProcessApp helper from mac-crafter's Signer - remove the WiX/MSI rule that stripped Qt6WebEngineCore.pdb - remove qt5.qtwebengine (and the now-dead isARM helper) from the Nix flake Co-Authored-By: Claude Opus 4.7 (1M context) Signed-off-by: Iva Horn --- CMakeLists.txt | 37 --- admin/nix/flake.nix | 6 +- .../mac-crafter/Sources/Commands/Build.swift | 6 +- .../mac-crafter/Sources/Utils/Signer.swift | 25 -- admin/win/msi/collect-transform.xsl.in | 4 - config.h.in | 2 - .../NextcloudDev/Craft.sh | 1 - src/gui/CMakeLists.txt | 12 - src/gui/creds/webflowcredentials.cpp | 38 +-- src/gui/creds/webflowcredentialsdialog.cpp | 55 +--- src/gui/creds/webflowcredentialsdialog.h | 18 +- src/gui/wizard/webview.cpp | 277 ------------------ src/gui/wizard/webview.h | 54 ---- src/gui/wizard/webview.ui | 80 ----- src/gui/wizard/webview.ui.license | 2 - src/libsync/configfile.cpp | 11 - src/libsync/configfile.h | 4 - src/libsync/networkjobs.cpp | 66 +---- src/libsync/networkjobs.h | 6 - 19 files changed, 22 insertions(+), 682 deletions(-) delete mode 100644 src/gui/wizard/webview.cpp delete mode 100644 src/gui/wizard/webview.h delete mode 100644 src/gui/wizard/webview.ui delete mode 100644 src/gui/wizard/webview.ui.license diff --git a/CMakeLists.txt b/CMakeLists.txt index ed437c0342b50..06409036ffabd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -271,43 +271,6 @@ if(BUILD_CLIENT) endif() endif() -option(BUILD_WITH_WEBENGINE "BUILD_WITH_WEBENGINE" ON) -if (BUILD_WITH_WEBENGINE) - find_package(Qt${QT_VERSION_MAJOR}WebEngineCore ${REQUIRED_QT_VERSION} CONFIG QUIET) - if(APPLE) - set_package_properties(Qt${QT_VERSION_MAJOR}WebEngineCore PROPERTIES - DESCRIPTION "Qt${QT_VERSION_MAJOR} WebEngineCore component." - TYPE RECOMMENDED - ) - else() - set_package_properties(Qt${QT_VERSION_MAJOR}WebEngineCore PROPERTIES - DESCRIPTION "Qt${QT_VERSION_MAJOR} WebEngine component." - TYPE REQUIRED - ) - endif() - - find_package(Qt${QT_MAJOR_VERSION}WebEngineWidgets ${REQUIRED_QT_VERSION} CONFIG QUIET) - if(APPLE) - set_package_properties(Qt${QT_MAJOR_VERSION}WebEngineWidgets PROPERTIES - DESCRIPTION "Qt${QT_MAJOR_VERSION} WebEngineWidgets component." - TYPE RECOMMENDED - ) - else() - set_package_properties(Qt${QT_MAJOR_VERSION}WebEngineWidgets PROPERTIES - DESCRIPTION "Qt${QT_MAJOR_VERSION} WebEngineWidgets component." - TYPE REQUIRED - ) - endif() - - if(Qt${QT_MAJOR_VERSION}WebEngineCore_FOUND AND Qt${QT_MAJOR_VERSION}WebEngineWidgets_FOUND) - message(STATUS "Enable use of Qt6 WebEngine module") - set(WITH_WEBENGINE 1) - else() - unset(WITH_WEBENGINE) - message(STATUS "Disable use of Qt6 WebEngine module") - endif() -endif() - if (NOT DEFINED APPLICATION_ICON_NAME) set(APPLICATION_ICON_NAME ${APPLICATION_SHORTNAME}) endif() diff --git a/admin/nix/flake.nix b/admin/nix/flake.nix index 0c1dc98cb3711..0f04cf98f3e78 100644 --- a/admin/nix/flake.nix +++ b/admin/nix/flake.nix @@ -20,8 +20,7 @@ }; inherit (pkgs.lib.lists) optional optionals; - inherit (pkgs.lib.strings) hasPrefix optionalString; - isARM = hasPrefix "aarch64" system; + inherit (pkgs.lib.strings) optionalString; buildMacOSSymlinks = pkgs.runCommand "nextcloud-build-symlinks" {} '' mkdir -p $out/bin @@ -53,9 +52,6 @@ libsForQt5.karchive libsForQt5.qtkeychain - ] ++ optionals (!isARM) [ - # Qt WebEngine not available on ARM - qt5.qtwebengine ] ++ optionals stdenv.isLinux [ inotify-tools libcloudproviders diff --git a/admin/osx/mac-crafter/Sources/Commands/Build.swift b/admin/osx/mac-crafter/Sources/Commands/Build.swift index 415b305756cb9..5d01e096c797b 100644 --- a/admin/osx/mac-crafter/Sources/Commands/Build.swift +++ b/admin/osx/mac-crafter/Sources/Commands/Build.swift @@ -89,9 +89,6 @@ struct Build: AsyncParsableCommand { @Flag(help: "Build File Provider Module.") var buildFileProviderModule = false - - @Flag(help: "Build without QtWebEngine.") - var withoutWebEngine = false @Flag(help: "Build without Sparkle auto-updater.") var disableAutoUpdater = false @@ -201,8 +198,7 @@ struct Build: AsyncParsableCommand { "\(craftBlueprintName).osxArchs=\(arch)", "\(craftBlueprintName).buildTests=\(buildTests ? "True" : "False")", "\(craftBlueprintName).buildMacOSBundle=\(disableAppBundle ? "False" : "True")", - "\(craftBlueprintName).buildFileProviderModule=\(buildFileProviderModule ? "True" : "False")", - "\(craftBlueprintName).buildWithWebEngine=\(withoutWebEngine ? "False" : "True")" + "\(craftBlueprintName).buildFileProviderModule=\(buildFileProviderModule ? "True" : "False")" ] if let overrideServerUrl { diff --git a/admin/osx/mac-crafter/Sources/Utils/Signer.swift b/admin/osx/mac-crafter/Sources/Utils/Signer.swift index adfb43a618132..f2988013d0441 100644 --- a/admin/osx/mac-crafter/Sources/Utils/Signer.swift +++ b/admin/osx/mac-crafter/Sources/Utils/Signer.swift @@ -127,30 +127,6 @@ enum Signer: Signing { return output.contains("Mach-O 64-bit executable") } - /// - /// Find and sign the Qt web engine helper app inside the QtWebEngineCore framework. - /// - /// This needs explicit treatment because codesign does not automatically sign it when signing the upstream framework bundle. - /// - private static func signQtWebEngineProcessApp(in bundle: URL, with codeSignIdentity: String) async { - let location = bundle - .appendingPathComponent("Contents") - .appendingPathComponent("Frameworks") - .appendingPathComponent("QtWebEngineCore.framework") - .appendingPathComponent("Versions") - .appendingPathComponent("A") - .appendingPathComponent("Helpers") - .appendingPathComponent("QtWebEngineProcess.app") - - let entitlements = location - .appendingPathComponent("Contents") - .appendingPathComponent("Resources") - .appendingPathComponent("QtWebEngineProcess") - .appendingPathExtension("entitlements") - - await sign(at: location, with: codeSignIdentity, entitlements: entitlements) - } - /// /// Find and sign the Sparkle downloader inside the Sparkle framework. /// @@ -278,7 +254,6 @@ enum Signer: Signing { await sign(at: extensionInMainBundle, with: codeSignIdentity, entitlements: extensionEntitlements) } - await signQtWebEngineProcessApp(in: location, with: codeSignIdentity) await signSparkleDownloader(in: location, with: codeSignIdentity) await signSparkleUpdaterApp(in: location, with: codeSignIdentity) await signSparkleInstaller(in: location, with: codeSignIdentity) diff --git a/admin/win/msi/collect-transform.xsl.in b/admin/win/msi/collect-transform.xsl.in index 124195e8b4331..12f11017a3a58 100644 --- a/admin/win/msi/collect-transform.xsl.in +++ b/admin/win/msi/collect-transform.xsl.in @@ -42,8 +42,4 @@ - - - - diff --git a/config.h.in b/config.h.in index 3159cdb9233b5..07c2ce4f079e7 100644 --- a/config.h.in +++ b/config.h.in @@ -65,8 +65,6 @@ #cmakedefine01 NEXTCLOUD_DEV -#cmakedefine WITH_WEBENGINE - #cmakedefine01 CLIENTSIDEENCRYPTION_ENFORCE_USB_TOKEN #cmakedefine ENCRYPTION_HARDWARE_TOKEN_DRIVER_PATH "@ENCRYPTION_HARDWARE_TOKEN_DRIVER_PATH@" diff --git a/shell_integration/MacOSX/NextcloudIntegration/NextcloudDev/Craft.sh b/shell_integration/MacOSX/NextcloudIntegration/NextcloudDev/Craft.sh index 48047922f927e..a98704627f90e 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/NextcloudDev/Craft.sh +++ b/shell_integration/MacOSX/NextcloudIntegration/NextcloudDev/Craft.sh @@ -37,5 +37,4 @@ swift run mac-crafter \ --disable-auto-updater \ --build-file-provider-module \ --code-sign-identity="Apple Development" \ - --without-web-engine \ "$DESKTOP_CLIENT_PROJECT_ROOT" diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 0a16af221914a..18beafcddd8fe 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -44,7 +44,6 @@ set(client_UI_SRCS mnemonicdialog.ui vfsdownloaderrordialog.ui wizard/flow2authwidget.ui - wizard/webview.ui ) qt_add_resources(client_UI_SRCS ../../resources.qrc ${CMAKE_SOURCE_DIR}/theme.qrc) @@ -242,13 +241,6 @@ if (NOT DISABLE_ACCOUNT_MIGRATION) ) endif() -if (WITH_WEBENGINE) - list(APPEND client_SRCS - wizard/webview.h - wizard/webview.cpp - ) -endif() - IF(BUILD_UPDATER) set(updater_SRCS updater/ocupdater.h @@ -527,10 +519,6 @@ foreach(FILE IN LISTS client_UI_SRCS) set_property(SOURCE ${FILE} PROPERTY SKIP_UNITY_BUILD_INCLUSION ON) endforeach() -if(WITH_WEBENGINE) - target_link_libraries(nextcloudCore PUBLIC Qt::WebEngineWidgets Qt::WebEngineCore) -endif() - set_target_properties(nextcloudCore PROPERTIES AUTOUIC ON diff --git a/src/gui/creds/webflowcredentials.cpp b/src/gui/creds/webflowcredentials.cpp index 25101cacd8b10..8c1306cc680bc 100644 --- a/src/gui/creds/webflowcredentials.cpp +++ b/src/gui/creds/webflowcredentials.cpp @@ -11,9 +11,6 @@ #include "account.h" #include "configfile.h" #include "theme.h" -#ifdef WITH_WEBENGINE -#include "wizard/webview.h" -#endif // WITH_WEBENGINE #include "webflowcredentialsdialog.h" #include "networkjobs.h" @@ -148,37 +145,16 @@ void WebFlowCredentials::fetchFromKeychain(const QString &appName) { } void WebFlowCredentials::askFromUser() { - // Determine if the old flow has to be used (GS for now) - // Do a DetermineAuthTypeJob to make sure that the server is still using Flow2 - auto job = new DetermineAuthTypeJob(_account->sharedFromThis(), this); - connect(job, &DetermineAuthTypeJob::authType, [this](DetermineAuthTypeJob::AuthType type) { - // LoginFlowV2 > WebViewFlow > Shib > Basic -#ifdef WITH_WEBENGINE - bool useFlow2 = (type != DetermineAuthTypeJob::WebViewFlow); -#else // WITH_WEBENGINE - Q_UNUSED(type) - bool useFlow2 = true; -#endif // WITH_WEBENGINE - - _askDialog = new WebFlowCredentialsDialog(_account, useFlow2); - - if (!useFlow2) { - QUrl url = _account->url(); - QString path = url.path() + "/index.php/login/flow"; - url.setPath(path); - _askDialog->setUrl(url); - } + _askDialog = new WebFlowCredentialsDialog(_account); - QString msg = tr("You have been logged out of your account %1 at %2. Please login again.") - .arg(_account->prettyName(), _account->url().toDisplayString()); - _askDialog->setInfo(msg); + QString msg = tr("You have been logged out of your account %1 at %2. Please login again.") + .arg(_account->prettyName(), _account->url().toDisplayString()); + _askDialog->setInfo(msg); - _askDialog->show(); + _askDialog->show(); - connect(_askDialog, &WebFlowCredentialsDialog::urlCatched, this, &WebFlowCredentials::slotAskFromUserCredentialsProvided); - connect(_askDialog, &WebFlowCredentialsDialog::onClose, this, &WebFlowCredentials::slotAskFromUserCancelled); - }); - job->start(); + connect(_askDialog, &WebFlowCredentialsDialog::urlCatched, this, &WebFlowCredentials::slotAskFromUserCredentialsProvided); + connect(_askDialog, &WebFlowCredentialsDialog::onClose, this, &WebFlowCredentials::slotAskFromUserCancelled); qCDebug(lcWebFlowCredentials()) << "User needs to reauth!"; } diff --git a/src/gui/creds/webflowcredentialsdialog.cpp b/src/gui/creds/webflowcredentialsdialog.cpp index 5524f150668e8..30be248e25d47 100644 --- a/src/gui/creds/webflowcredentialsdialog.cpp +++ b/src/gui/creds/webflowcredentialsdialog.cpp @@ -5,17 +5,11 @@ #include "webflowcredentialsdialog.h" -#include "config.h" - #include "theme.h" #include "application.h" #include "guiutility.h" #include "owncloudgui.h" -#ifdef WITH_WEBENGINE -#include "wizard/webview.h" -#endif // WITH_WEBENGINE - #include "wizard/flow2authwidget.h" #include @@ -23,9 +17,8 @@ namespace OCC { -WebFlowCredentialsDialog::WebFlowCredentialsDialog(Account *account, bool useFlow2, QWidget *parent) +WebFlowCredentialsDialog::WebFlowCredentialsDialog(Account *account, QWidget *parent) : QDialog(parent) - , _useFlow2(useFlow2) { setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); @@ -44,27 +37,18 @@ WebFlowCredentialsDialog::WebFlowCredentialsDialog(Account *account, bool useFlo _infoLabel->setAlignment(Qt::AlignCenter); _containerLayout->addWidget(_infoLabel); - if (_useFlow2) { - _flow2AuthWidget = new Flow2AuthWidget(); - _containerLayout->addWidget(_flow2AuthWidget); - - connect(_flow2AuthWidget, &Flow2AuthWidget::authResult, this, &WebFlowCredentialsDialog::slotFlow2AuthResult); + _flow2AuthWidget = new Flow2AuthWidget(); + _containerLayout->addWidget(_flow2AuthWidget); - // Connect styleChanged events to our widgets, so they can adapt (Dark-/Light-Mode switching) - connect(this, &WebFlowCredentialsDialog::styleChanged, _flow2AuthWidget, &Flow2AuthWidget::slotStyleChanged); + connect(_flow2AuthWidget, &Flow2AuthWidget::authResult, this, &WebFlowCredentialsDialog::slotFlow2AuthResult); - // allow Flow2 page to poll on window activation - connect(this, &WebFlowCredentialsDialog::onActivate, _flow2AuthWidget, &Flow2AuthWidget::slotPollNow); + // Connect styleChanged events to our widgets, so they can adapt (Dark-/Light-Mode switching) + connect(this, &WebFlowCredentialsDialog::styleChanged, _flow2AuthWidget, &Flow2AuthWidget::slotStyleChanged); - _flow2AuthWidget->startAuth(account); - } else { -#ifdef WITH_WEBENGINE - _webView = new WebView(); - _containerLayout->addWidget(_webView, 1); + // allow Flow2 page to poll on window activation + connect(this, &WebFlowCredentialsDialog::onActivate, _flow2AuthWidget, &Flow2AuthWidget::slotPollNow); - connect(_webView, &WebView::urlCatched, this, &WebFlowCredentialsDialog::urlCatched); -#endif // WITH_WEBENGINE - } + _flow2AuthWidget->startAuth(account); auto app = dynamic_cast(qApp); connect(app, &Application::isShowingSettingsDialog, this, &WebFlowCredentialsDialog::slotShowSettingsDialog); @@ -85,15 +69,6 @@ WebFlowCredentialsDialog::WebFlowCredentialsDialog(Account *account, bool useFlo void WebFlowCredentialsDialog::closeEvent(QCloseEvent* e) { Q_UNUSED(e) -#ifdef WITH_WEBENGINE - if (_webView) { - // Force calling WebView::~WebView() earlier so that _profile and _page are - // deleted in the correct order. - _webView->deleteLater(); - _webView = nullptr; - } -#endif // WITH_WEBENGINE - if (_flow2AuthWidget) { _flow2AuthWidget->resetAuth(); _flow2AuthWidget->deleteLater(); @@ -103,16 +78,6 @@ void WebFlowCredentialsDialog::closeEvent(QCloseEvent* e) { emit onClose(); } -void WebFlowCredentialsDialog::setUrl(const QUrl &url) -{ -#ifdef WITH_WEBENGINE - if (_webView) - _webView->setUrl(url); -#else // WITH_WEBENGINE - Q_UNUSED(url); -#endif // WITH_WEBENGINE -} - void WebFlowCredentialsDialog::setInfo(const QString &msg) { _infoLabel->setText(msg); } @@ -121,7 +86,7 @@ void WebFlowCredentialsDialog::setError(const QString &error) { // bring window to top slotShowSettingsDialog(); - if (_useFlow2 && _flow2AuthWidget) { + if (_flow2AuthWidget) { _flow2AuthWidget->setError(error); return; } diff --git a/src/gui/creds/webflowcredentialsdialog.h b/src/gui/creds/webflowcredentialsdialog.h index ed140736ed39f..64bb3c40faaeb 100644 --- a/src/gui/creds/webflowcredentialsdialog.h +++ b/src/gui/creds/webflowcredentialsdialog.h @@ -6,38 +6,27 @@ #ifndef WEBFLOWCREDENTIALSDIALOG_H #define WEBFLOWCREDENTIALSDIALOG_H -#include "config.h" - #include "accountfwd.h" #include "creds/flow2auth.h" #include -#include class QLabel; class QVBoxLayout; namespace OCC { -#ifdef WITH_WEBENGINE -class WebView; -#endif // WITH_WEBENGINE class Flow2AuthWidget; class WebFlowCredentialsDialog : public QDialog { Q_OBJECT public: - WebFlowCredentialsDialog(Account *account, bool useFlow2, QWidget *parent = nullptr); + WebFlowCredentialsDialog(Account *account, QWidget *parent = nullptr); - void setUrl(const QUrl &url); void setInfo(const QString &msg); void setError(const QString &error); - [[nodiscard]] bool isUsingFlow2() const { - return _useFlow2; - } - protected: void closeEvent(QCloseEvent * e) override; void changeEvent(QEvent *) override; @@ -55,12 +44,7 @@ public slots: private: void customizeStyle(); - bool _useFlow2; - Flow2AuthWidget *_flow2AuthWidget = nullptr; -#ifdef WITH_WEBENGINE - WebView *_webView = nullptr; -#endif // WITH_WEBENGINE QLabel *_errorLabel; QLabel *_infoLabel; diff --git a/src/gui/wizard/webview.cpp b/src/gui/wizard/webview.cpp deleted file mode 100644 index 8e661a0b6a82d..0000000000000 --- a/src/gui/wizard/webview.cpp +++ /dev/null @@ -1,277 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors - * SPDX-License-Identifier: GPL-2.0-or-later - */ - -#include "webview.h" - -#include -#include -#include -#include -#if QT_VERSION >= 0x051200 -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include - -#include "guiutility.h" -#include "common/utility.h" - -namespace OCC { - -Q_LOGGING_CATEGORY(lcWizardWebiew, "nextcloud.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 { - Q_OBJECT -public: - WebEnginePage(QWebEngineProfile *profile, QObject* parent = nullptr); - QWebEnginePage * createWindow(QWebEnginePage::WebWindowType type) override; - void setUrl(const QUrl &url); - -protected: - bool slotCertificateError(const QWebEngineCertificateError &certificateError); - - bool acceptNavigationRequest(const QUrl &url, QWebEnginePage::NavigationType type, bool isMainFrame) override; - -private: - bool _enforceHttps = false; -}; - -// We need a separate class here, since we cannot simply return the same WebEnginePage object -// this leads to a strange segfault somewhere deep inside of the QWebEngine code -class ExternalWebEnginePage : public QWebEnginePage { - Q_OBJECT -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); -#if QT_VERSION >= 0x051200 - QWebEngineUrlScheme _ncsheme("nc"); - QWebEngineUrlScheme::registerScheme(_ncsheme); -#endif - _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->setUrlRequestInterceptor(_interceptor); - _profile->installUrlSchemeHandler("nc", _schemeHandler); - - /* - * Set a proper accept language 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, 1); - - connect(_webview, &QWebEngineView::loadProgress, _ui.progressBar, &QProgressBar::setValue); - connect(_schemeHandler, &WebViewPageUrlSchemeHandler::urlCatched, this, &WebView::urlCatched); - - connect(_page, &QWebEnginePage::contentsSizeChanged, this, &WebView::slotResizeToContents); -} - -void WebView::setUrl(const QUrl &url) { - _page->setUrl(url); -} - -QSize WebView::minimumSizeHint() const { - return _size; -} - -void WebView::slotResizeToContents(const QSizeF &size){ - //this widget also holds the progressbar - const int newHeight = size.toSize().height() + _ui.progressBar->height(); - const int newWidth = size.toSize().width(); - _size = QSize(newWidth, newHeight); - - this->updateGeometry(); - - //only resize once - disconnect(_page, &QWebEnginePage::contentsSizeChanged, this, &WebView::slotResizeToContents); -} - -WebView::~WebView() { - /* - * The Qt implementation 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) { - if (info.initiator().isEmpty()) { - info.setHttpHeader("OCS-APIREQUEST", "true"); - qCDebug(lcWizardWebiew()) << info.requestMethod() << "add extra header" << "OCS-APIREQUEST"; - } -} - -WebViewPageUrlSchemeHandler::WebViewPageUrlSchemeHandler(QObject *parent) - : QWebEngineUrlSchemeHandler(parent) { - -} - -void WebViewPageUrlSchemeHandler::requestStarted(QWebEngineUrlRequestJob *request) { - QUrl url = request->requestUrl(); - - QString path = url.path().mid(1); // get undecoded path - const 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) -{ - connect(this, &QWebEnginePage::certificateError, - this, &WebEnginePage::slotCertificateError); -} - -QWebEnginePage * WebEnginePage::createWindow(QWebEnginePage::WebWindowType type) { - Q_UNUSED(type); - auto *view = new ExternalWebEnginePage(this->profile()); - return view; -} - -void WebEnginePage::setUrl(const QUrl &url) -{ - QWebEnginePage::setUrl(url); - _enforceHttps = url.scheme() == QStringLiteral("https"); -} - -bool WebEnginePage::slotCertificateError(const QWebEngineCertificateError &certificateError) -{ - /** - * 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; -} - -bool WebEnginePage::acceptNavigationRequest(const QUrl &url, QWebEnginePage::NavigationType type, bool isMainFrame) -{ - Q_UNUSED(type); - Q_UNUSED(isMainFrame); - - if (_enforceHttps && url.scheme() != QStringLiteral("https") && url.scheme() != QStringLiteral("nc")) { - QMessageBox::warning(nullptr, "Security warning", "Can not follow non https link on a https website. This might be a security issue. Please contact your administrator"); - return false; - } - return true; -} - -ExternalWebEnginePage::ExternalWebEnginePage(QWebEngineProfile *profile, QObject* parent) : QWebEnginePage(profile, parent) { - -} - - -bool ExternalWebEnginePage::acceptNavigationRequest(const QUrl &url, QWebEnginePage::NavigationType type, bool isMainFrame) -{ - Q_UNUSED(type); - Q_UNUSED(isMainFrame); - Utility::openBrowser(url); - return false; -} - -} - -#include "webview.moc" diff --git a/src/gui/wizard/webview.h b/src/gui/wizard/webview.h deleted file mode 100644 index 5ba6aaa6bea00..0000000000000 --- a/src/gui/wizard/webview.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors - * SPDX-License-Identifier: GPL-2.0-or-later - */ - -#ifndef WEBVIEW_H -#define WEBVIEW_H - -#include -#include - -#include "ui_webview.h" - -class QWebEngineView; -class QWebEngineProfile; -class QWebEnginePage; - -namespace OCC { - -class WebViewPageUrlRequestInterceptor; -class WebViewPageUrlSchemeHandler; -class WebEnginePage; - -class WebView : public QWidget -{ - Q_OBJECT -public: - WebView(QWidget *parent = nullptr); - ~WebView() override; - void setUrl(const QUrl &url); - virtual QSize minimumSizeHint() const override; - -signals: - void urlCatched(const QString user, const QString pass, const QString host); - -private slots: - void slotResizeToContents(const QSizeF &size); - -private: - Ui_WebView _ui; - - QSize _size; - - QWebEngineView *_webview; - QWebEngineProfile *_profile; - WebEnginePage *_page; - - WebViewPageUrlRequestInterceptor *_interceptor; - WebViewPageUrlSchemeHandler *_schemeHandler; -}; - -} - -#endif // WEBVIEW_H diff --git a/src/gui/wizard/webview.ui b/src/gui/wizard/webview.ui deleted file mode 100644 index 8ab0665b78714..0000000000000 --- a/src/gui/wizard/webview.ui +++ /dev/null @@ -1,80 +0,0 @@ - - - WebView - - - - 0 - 0 - 800 - 700 - - - - - 0 - 0 - - - - - 0 - 0 - - - - Form - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - 0 - - - - - - 16777215 - 5 - - - - QProgressBar::chunk { - background-color: rgba(0, 130, 201, 255); -} - - - 0 - - - false - - - - - - - 0 - - - - - - - - - - diff --git a/src/gui/wizard/webview.ui.license b/src/gui/wizard/webview.ui.license deleted file mode 100644 index ab46ca46759e6..0000000000000 --- a/src/gui/wizard/webview.ui.license +++ /dev/null @@ -1,2 +0,0 @@ -SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors -SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/libsync/configfile.cpp b/src/libsync/configfile.cpp index fd31f0264e09b..63767eeb05a0a 100644 --- a/src/libsync/configfile.cpp +++ b/src/libsync/configfile.cpp @@ -69,7 +69,6 @@ static constexpr char proxyPortC[] = "Proxy/port"; static constexpr char proxyUserC[] = "Proxy/user"; static constexpr char proxyPassC[] = "Proxy/pass"; static constexpr char proxyNeedsAuthC[] = "Proxy/needsAuth"; -static constexpr char forceLoginV2C[] = "forceLoginV2"; static constexpr char certPath[] = "http_certificatePath"; static constexpr char certPasswd[] = "http_certificatePasswd"; @@ -1058,16 +1057,6 @@ void ConfigFile::setMoveToTrash(bool isChecked) setValue(moveToTrashC, isChecked); } -bool ConfigFile::forceLoginV2() const -{ - return getValue(forceLoginV2C, QString(), false).toBool(); -} - -void ConfigFile::setForceLoginV2(bool isChecked) -{ - setValue(forceLoginV2C, isChecked); -} - bool ConfigFile::showMainDialogAsNormalWindow() const { return getValue(showMainDialogAsNormalWindowC, {}, false).toBool(); } diff --git a/src/libsync/configfile.h b/src/libsync/configfile.h index 14a5968970e11..60af427800000 100644 --- a/src/libsync/configfile.h +++ b/src/libsync/configfile.h @@ -149,10 +149,6 @@ class OWNCLOUDSYNC_EXPORT ConfigFile [[nodiscard]] bool moveToTrash() const; void setMoveToTrash(bool); - /** If we should force loginflow v2 */ - [[nodiscard]] bool forceLoginV2() const; - void setForceLoginV2(bool); - [[nodiscard]] bool showMainDialogAsNormalWindow() const; static bool setConfDir(const QString &value); diff --git a/src/libsync/networkjobs.cpp b/src/libsync/networkjobs.cpp index 8cd4709d96f5b..1dee03fa828f2 100644 --- a/src/libsync/networkjobs.cpp +++ b/src/libsync/networkjobs.cpp @@ -1171,7 +1171,6 @@ DetermineAuthTypeJob::DetermineAuthTypeJob(AccountPtr account, QObject *parent) : QObject(parent) , _account(account) { - useFlow2 = ConfigFile().forceLoginV2(); } void DetermineAuthTypeJob::start() @@ -1184,7 +1183,7 @@ void DetermineAuthTypeJob::start() // Don't reuse previous auth credentials req.setAttribute(QNetworkRequest::AuthenticationReuseAttribute, QNetworkRequest::Manual); - // Start three parallel requests + // Start two parallel requests // 1. determines whether it's a basic auth server auto get = _account->sendRequest("GET", _account->url(), req); @@ -1192,15 +1191,10 @@ void DetermineAuthTypeJob::start() // 2. checks the HTTP auth method. auto propfind = _account->sendRequest("PROPFIND", _account->davUrl(), req); - // 3. Determines if the old flow has to be used (GS for now) - auto oldFlowRequired = new JsonApiJob(_account, "/ocs/v2.php/cloud/capabilities", this); - get->setTimeout(30 * 1000); propfind->setTimeout(30 * 1000); - oldFlowRequired->setTimeout(30 * 1000); get->setIgnoreCredentialFailure(true); propfind->setIgnoreCredentialFailure(true); - oldFlowRequired->setIgnoreCredentialFailure(true); connect(get, &SimpleNetworkJob::finishedSignal, this, [this, get]() { const auto reply = get->reply(); @@ -1229,79 +1223,23 @@ void DetermineAuthTypeJob::start() _propfindDone = true; checkAllDone(); }); - connect(oldFlowRequired, &JsonApiJob::jsonReceived, this, [this](const QJsonDocument &json, int statusCode) { - if (statusCode == 200) { - _resultOldFlow = LoginFlowV2; - - auto data = json.object().value("ocs").toObject().value("data").toObject().value("capabilities").toObject(); - auto gs = data.value("globalscale"); - if (gs != QJsonValue::Undefined) { - auto flow = gs.toObject().value("desktoplogin"); - if (flow != QJsonValue::Undefined) { - if (flow.toInt() == 1) { -#ifdef WITH_WEBENGINE - if(!this->useFlow2) { - _resultOldFlow = WebViewFlow; - } else { - qCWarning(lcDetermineAuthTypeJob) << "Server only supports flow1, but this client was configured to only use flow2"; - } -#else // WITH_WEBENGINE - qCWarning(lcDetermineAuthTypeJob) << "Server does only support flow1, but this client was compiled without support for flow1"; -#endif // WITH_WEBENGINE - } - } - } - } else { - _resultOldFlow = Basic; - } - if (_account->isPublicShareLink()) { - _resultOldFlow = Basic; - } - _oldFlowDone = true; - checkAllDone(); - }); - - oldFlowRequired->start(); } void DetermineAuthTypeJob::checkAllDone() { - // Do not conitunue until eve - if (!_getDone || !_propfindDone || !_oldFlowDone) { + if (!_getDone || !_propfindDone) { return; } Q_ASSERT(_resultGet != NoAuthType); Q_ASSERT(_resultPropfind != NoAuthType); - Q_ASSERT(_resultOldFlow != NoAuthType); auto result = _resultPropfind; -#ifdef WITH_WEBENGINE - // WebViewFlow > Basic - if (_account->serverVersionInt() >= Account::makeServerVersion(12, 0, 0)) { - result = WebViewFlow; - if (useFlow2) { - result = LoginFlowV2; - } - } -#endif // WITH_WEBENGINE - - // LoginFlowV2 > WebViewFlow > Basic if (_account->serverVersionInt() >= Account::makeServerVersion(16, 0, 0)) { result = LoginFlowV2; } -#ifdef WITH_WEBENGINE - // If we determined that we need the webview flow (GS for example) then we switch to that - if (_resultOldFlow == WebViewFlow) { - result = WebViewFlow; - if (useFlow2) { - result = LoginFlowV2; - } - } -#endif // WITH_WEBENGINE - // If we determined that a simple get gave us an authentication required error // then the server enforces basic auth and we got no choice but to use this if (_resultGet == Basic) { diff --git a/src/libsync/networkjobs.h b/src/libsync/networkjobs.h index 4e5b9c485be9c..053a0cf0f778a 100644 --- a/src/libsync/networkjobs.h +++ b/src/libsync/networkjobs.h @@ -532,9 +532,6 @@ class OWNCLOUDSYNC_EXPORT DetermineAuthTypeJob : public QObject public: enum AuthType { NoAuthType, // used only before we got a chance to probe the server -#ifdef WITH_WEBENGINE - WebViewFlow, -#endif // WITH_WEBENGINE Basic, // also the catch-all fallback for backwards compatibility reasons LoginFlowV2 }; @@ -551,11 +548,8 @@ class OWNCLOUDSYNC_EXPORT DetermineAuthTypeJob : public QObject AccountPtr _account; AuthType _resultGet = NoAuthType; AuthType _resultPropfind = NoAuthType; - AuthType _resultOldFlow = NoAuthType; bool _getDone = false; bool _propfindDone = false; - bool _oldFlowDone = false; - bool useFlow2 = false; }; /**