diff --git a/config.h.in b/config.h.in index e4f46791fb..8d6096ccf1 100644 --- a/config.h.in +++ b/config.h.in @@ -35,7 +35,7 @@ #define APPLICATION_URI_HANDLER_SCHEME "@APPLICATION_URI_HANDLER_SCHEME@" #cmakedefine01 ENFORCE_VIRTUAL_FILES_SYNC_FOLDER #cmakedefine01 DISABLE_VIRTUAL_FILES_SYNC_FOLDER -#cmakedefine DO_NOT_USE_PROXY "@DO_NOT_USE_PROXY@" +#cmakedefine01 DO_NOT_USE_PROXY #cmakedefine ENFORCE_SINGLE_ACCOUNT "@ENFORCE_SINGLE_ACCOUNT@" #cmakedefine01 APPLICATION_DISPLAY_LEGACY_IMPORT_DIALOG #cmakedefine01 DISABLE_ACCOUNT_MIGRATION diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index d389df77d7..a9491e5be5 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -49,6 +49,7 @@ set(client_UI_SRCS wizard/termsofservicecheckwidget.ui wizard/webview.ui wizard/welcomepage.ui + wizard/proxysettings.ui ) qt_add_resources(client_UI_SRCS ../../resources.qrc ${CMAKE_SOURCE_DIR}/theme.qrc) @@ -254,6 +255,8 @@ set(client_SRCS wizard/welcomepage.cpp wizard/linklabel.h wizard/linklabel.cpp + wizard/wizardproxysettingsdialog.h + wizard/wizardproxysettingsdialog.cpp ) if (NOT DISABLE_ACCOUNT_MIGRATION) diff --git a/src/gui/owncloudsetupwizard.cpp b/src/gui/owncloudsetupwizard.cpp index ba7ded88ec..0116b23901 100644 --- a/src/gui/owncloudsetupwizard.cpp +++ b/src/gui/owncloudsetupwizard.cpp @@ -146,20 +146,34 @@ void OwncloudSetupWizard::startWizard() } // also checks if an installation is valid and determines auth type in a second step -void OwncloudSetupWizard::slotCheckServer(const QString &urlString) +void OwncloudSetupWizard::slotCheckServer(const QUrl &serverURL, const OCC::WizardProxySettingsDialog::WizardProxySettings &proxySettings) { - QString fixedUrl = urlString; - QUrl url = QUrl::fromUserInput(fixedUrl); - // fromUserInput defaults to http, not http if no scheme is specified - if (!fixedUrl.startsWith("http://") && !fixedUrl.startsWith("https://")) { - url.setScheme("https"); - } AccountPtr account = _ocWizard->account(); - account->setUrl(url); + account->setUrl(serverURL); - // Reset the proxy which might had been determined previously in ConnectionValidator::checkServerAndAuth() - // when there was a previous account. - account->networkAccessManager()->setProxy(QNetworkProxy(QNetworkProxy::NoProxy)); + account->setProxyType(proxySettings._proxyType); + switch (proxySettings._proxyType) + { + case QNetworkProxy::HttpCachingProxy: + case QNetworkProxy::FtpCachingProxy: + case QNetworkProxy::NoProxy: + case QNetworkProxy::ProxyType::DefaultProxy: + // Reset the proxy which might had been determined previously in ConnectionValidator::checkServerAndAuth() + // when there was a previous account. + account->networkAccessManager()->setProxy({QNetworkProxy::NoProxy}); + break; + case QNetworkProxy::Socks5Proxy: + case QNetworkProxy::HttpProxy: + account->setProxyHostName(proxySettings._host); + account->setProxyPort(proxySettings._port); + account->setProxyNeedsAuth(proxySettings._needsAuth == WizardProxySettingsDialog::ProxyAuthentication::AuthenticationRequired); + if (account->proxyNeedsAuth()) { + account->setProxyUser(proxySettings._user); + account->setProxyPassword(proxySettings._password); + } + + break; + } // And also reset the QSslConfiguration, for the same reason (#6832) // Here the client certificate is added, if any. Later it'll be in HttpCredentials diff --git a/src/gui/owncloudsetupwizard.h b/src/gui/owncloudsetupwizard.h index af09ee2123..cdc64001fe 100644 --- a/src/gui/owncloudsetupwizard.h +++ b/src/gui/owncloudsetupwizard.h @@ -17,7 +17,7 @@ #include "theme.h" #include "networkjobs.h" -#include "wizard/owncloudwizardcommon.h" +#include "wizard/wizardproxysettingsdialog.h" namespace OCC { @@ -43,7 +43,7 @@ signals: void ownCloudWizardDone(int); private slots: - void slotCheckServer(const QString &); + void slotCheckServer(const QUrl &serverURL, const OCC::WizardProxySettingsDialog::WizardProxySettings &proxySettings); void slotSystemProxyLookupDone(const QNetworkProxy &proxy); void slotFindServer(); diff --git a/src/gui/wizard/owncloudsetupnocredspage.ui b/src/gui/wizard/owncloudsetupnocredspage.ui index d12a9e1438..62391b1689 100644 --- a/src/gui/wizard/owncloudsetupnocredspage.ui +++ b/src/gui/wizard/owncloudsetupnocredspage.ui @@ -36,10 +36,10 @@ - Qt::Vertical + Qt::Orientation::Vertical - QSizePolicy::Expanding + QSizePolicy::Policy::Expanding @@ -57,7 +57,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -77,7 +77,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -92,10 +92,10 @@ - Qt::Vertical + Qt::Orientation::Vertical - QSizePolicy::Minimum + QSizePolicy::Policy::Minimum @@ -129,7 +129,7 @@ 0 - QLayout::SetDefaultConstraint + QLayout::SizeConstraint::SetDefaultConstraint @@ -139,10 +139,10 @@ - Qt::Vertical + Qt::Orientation::Vertical - QSizePolicy::Minimum + QSizePolicy::Policy::Minimum @@ -160,7 +160,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -175,7 +175,6 @@ 12 - 75 true @@ -187,7 +186,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -210,10 +209,10 @@ - Qt::Horizontal + Qt::Orientation::Horizontal - QSizePolicy::Expanding + QSizePolicy::Policy::Expanding @@ -262,7 +261,7 @@ This is the link to your %1 web interface when you open it in the browser. - Qt::AlignCenter + Qt::AlignmentFlag::AlignCenter true @@ -274,10 +273,10 @@ - Qt::Horizontal + Qt::Orientation::Horizontal - QSizePolicy::Expanding + QSizePolicy::Policy::Expanding @@ -301,7 +300,7 @@ Error Label - Qt::RichText + Qt::TextFormat::RichText true @@ -314,10 +313,10 @@ - Qt::Vertical + Qt::Orientation::Vertical - QSizePolicy::MinimumExpanding + QSizePolicy::Policy::MinimumExpanding @@ -337,10 +336,10 @@ - Qt::Vertical + Qt::Orientation::Vertical - QSizePolicy::MinimumExpanding + QSizePolicy::Policy::MinimumExpanding diff --git a/src/gui/wizard/owncloudsetuppage.cpp b/src/gui/wizard/owncloudsetuppage.cpp index 156deaf0f3..616d6527b2 100644 --- a/src/gui/wizard/owncloudsetuppage.cpp +++ b/src/gui/wizard/owncloudsetuppage.cpp @@ -18,13 +18,14 @@ #include #include #include +#include #include "QProgressIndicator.h" #include "wizard/owncloudwizardcommon.h" #include "wizard/owncloudsetuppage.h" #include "wizard/owncloudconnectionmethoddialog.h" -#include "wizard/slideshow.h" +#include "wizard/wizardproxysettingsdialog.h" #include "theme.h" #include "account.h" #include "config.h" @@ -80,6 +81,7 @@ OwncloudSetupPage::OwncloudSetupPage(QWidget *parent) addCertDial = new AddCertificateDialog(this); connect(addCertDial, &QDialog::accepted, this, &OwncloudSetupPage::slotCertificateAccepted); + } void OwncloudSetupPage::setLogo() @@ -93,6 +95,41 @@ void OwncloudSetupPage::setupServerAddressDescriptionLabel() _ui.serverAddressDescriptionLabel->setText(tr("The link to your %1 web interface when you open it in the browser.", "%1 will be replaced with the application name").arg(appName)); } +void OwncloudSetupPage::setProxySettingsButtonEnabled(bool enable) +{ + const auto proxySettingsButton = getProxySettingsButton(); + + if (!proxySettingsButton) { + return; + } + + proxySettingsButton->setEnabled(enable); +} + +void OwncloudSetupPage::setProxySettingsButtonVisible(bool visible) +{ + const auto proxySettingsButton = getProxySettingsButton(); + + if (!proxySettingsButton) { + return; + } + + proxySettingsButton->setVisible(visible); +} + +QAbstractButton *OwncloudSetupPage::getProxySettingsButton() const +{ + auto result = static_cast(nullptr); + + if (!wizard()) { + return result; + } + + result = wizard()->button(QWizard::CustomButton3); + + return result; +} + void OwncloudSetupPage::setServerUrl(const QString &newUrl) { _ocWizard->setRegistration(false); @@ -158,6 +195,7 @@ void OwncloudSetupPage::slotUrlChanged(const QString &url) if (newUrl != url) { _ui.leUrl->setText(newUrl); } + setProxySettingsButtonEnabled(!_ui.leUrl->fullText().isEmpty()); } void OwncloudSetupPage::slotUrlEditFinished() @@ -170,6 +208,20 @@ void OwncloudSetupPage::slotUrlEditFinished() } } +void OwncloudSetupPage::slotSetProxySettings() +{ + if (!_proxySettingsDialog) { + _proxySettingsDialog = new WizardProxySettingsDialog{QUrl::fromUserInput(_ui.leUrl->fullText()), _proxySettings, this}; + + connect(_proxySettingsDialog, &WizardProxySettingsDialog::proxySettingsAccepted, this, [this] (const OCC::WizardProxySettingsDialog::WizardProxySettings &proxySettings) { _proxySettings = proxySettings;}); + } else { + _proxySettingsDialog->setServerUrl(QUrl::fromUserInput(_ui.leUrl->fullText())); + _proxySettingsDialog->setProxySettings(_proxySettings); + } + + _proxySettingsDialog->open(); +} + bool OwncloudSetupPage::isComplete() const { return (!_ui.leUrl->text().isEmpty() || !_ui.comboBox->currentData().toString().isEmpty()) && !_checking; @@ -209,6 +261,23 @@ void OwncloudSetupPage::initializePage() validatePage(); setVisible(false); } + + setProxySettingsButtonEnabled(false); + ensureProxySettingsButtonIsConnected(); +} + +void OwncloudSetupPage::ensureProxySettingsButtonIsConnected() +{ + const auto proxySettingsButton = getProxySettingsButton(); + + if (!proxySettingsButton) { + return; + } + + disconnect(_proxyButtonIsConnected); + + _proxyButtonIsConnected = connect(proxySettingsButton, &QPushButton::clicked, + this, &OwncloudSetupPage::slotSetProxySettings); } int OwncloudSetupPage::nextId() const @@ -245,8 +314,8 @@ bool OwncloudSetupPage::validatePage() { if (!_authTypeKnown) { slotUrlEditFinished(); - QString u = url(); - QUrl qurl(u); + const auto urlString = url(); + const auto qurl = QUrl::fromUserInput(urlString); if (!qurl.isValid() || qurl.host().isEmpty()) { setErrorString(tr("Server address does not seem to be valid"), false); return false; @@ -257,7 +326,7 @@ bool OwncloudSetupPage::validatePage() startSpinner(); emit completeChanged(); - emit determineAuthType(u); + Q_EMIT determineAuthType(qurl, _proxySettings); return false; } else { // connecting is running @@ -282,7 +351,7 @@ void OwncloudSetupPage::setErrorString(const QString &err, bool retryHTTPonly) } else { if (retryHTTPonly) { const auto urlString = url(); - QUrl url(urlString); + auto url = QUrl::fromUserInput(urlString); if (url.scheme() == "https") { // Ask the user how to proceed when connecting to a https:// URL fails. // It is possible that the server is secured with client-side TLS certificates, diff --git a/src/gui/wizard/owncloudsetuppage.h b/src/gui/wizard/owncloudsetuppage.h index cd898c901b..549487064a 100644 --- a/src/gui/wizard/owncloudsetuppage.h +++ b/src/gui/wizard/owncloudsetuppage.h @@ -9,16 +9,13 @@ #include -#include "wizard/owncloudwizardcommon.h" #include "wizard/owncloudwizard.h" #include "../addcertificatedialog.h" -#include "wizard/owncloudconnectionmethoddialog.h" +#include "wizard/wizardproxysettingsdialog.h" #include "ui_owncloudsetupnocredspage.h" -#include "config.h" - class QLabel; class QVariant; class QProgressIndicator; @@ -59,16 +56,23 @@ protected slots: void slotUrlChanged(const QString &); void slotUrlEditFinished(); + void slotSetProxySettings(); + void setupCustomization(); signals: - void determineAuthType(const QString &); + void determineAuthType(const QUrl &serverURL, const OCC::WizardProxySettingsDialog::WizardProxySettings &proxySettings); private: void setLogo(); void customizeStyle(); void setupServerAddressDescriptionLabel(); + void setProxySettingsButtonEnabled(bool enable); + void setProxySettingsButtonVisible(bool visible); + [[nodiscard]] QAbstractButton* getProxySettingsButton() const; + void ensureProxySettingsButtonIsConnected(); + Ui_OwncloudSetupPage _ui{}; QString _oCUrl; @@ -81,6 +85,10 @@ private: OwncloudWizard *_ocWizard; AddCertificateDialog *addCertDial = nullptr; + WizardProxySettingsDialog *_proxySettingsDialog = nullptr; + WizardProxySettingsDialog::WizardProxySettings _proxySettings; + QMetaObject::Connection _proxyButtonIsConnected; + // Grab the forceLoginV2-setting from the wizard bool useFlow2 = _ocWizard->useFlow2(); }; diff --git a/src/gui/wizard/owncloudwizard.cpp b/src/gui/wizard/owncloudwizard.cpp index 536fb37be1..126ee2b5bb 100644 --- a/src/gui/wizard/owncloudwizard.cpp +++ b/src/gui/wizard/owncloudwizard.cpp @@ -98,6 +98,10 @@ OwncloudWizard::OwncloudWizard(QWidget *parent) setOption(QWizard::NoCancelButton); setButtonText(QWizard::CustomButton1, tr("Skip folders configuration")); setButtonText(QWizard::CustomButton2, tr("Cancel")); + setButtonText(QWizard::CustomButton3, tr("Proxy Settings", "Proxy Settings button text in new account wizard")); + + setButtonText(QWizard::NextButton, tr("Next", "Next button text in new account wizard")); + setButtonText(QWizard::BackButton, tr("Back", "Next button text in new account wizard")); // Change the next buttons size policy since we hide it on the // welcome page but want it to fill it's space that we don't get @@ -163,6 +167,12 @@ QList OwncloudWizard::calculateWizardPageSizes() const return pageSizes; } +void OwncloudWizard::ensureWelcomePageCorrectLayout() +{ + setButtonLayout({QWizard::NextButton}); + button(QWizard::NextButton)->setHidden(true); +} + QSize OwncloudWizard::calculateLargestSizeOfWizardPages(const QList &pageSizes) const { QSize largestSize; @@ -330,8 +340,8 @@ void OwncloudWizard::slotCurrentPageChanged(int id) }; if (id == WizardCommon::Page_Welcome) { - // Set next button to just hidden so it retains it's layout - button(QWizard::NextButton)->setHidden(true); + ensureWelcomePageCorrectLayout(); + // Need to set it from here, otherwise it has no effect _welcomePage->setLoginButtonDefault(); } else if ( @@ -340,12 +350,19 @@ void OwncloudWizard::slotCurrentPageChanged(int id) #endif // WITH_WEBENGINE id == WizardCommon::Page_Flow2AuthCreds || id == WizardCommon::Page_TermsOfService) { - setButtonLayout({ QWizard::BackButton, QWizard::Stretch }); + setButtonLayout({QWizard::BackButton, QWizard::Stretch}); } else if (id == WizardCommon::Page_AdvancedSetup) { - setButtonLayout({ QWizard::CustomButton2, QWizard::Stretch, QWizard::CustomButton1, QWizard::FinishButton }); + setButtonLayout({QWizard::CustomButton2, QWizard::Stretch, QWizard::CustomButton1, QWizard::FinishButton}); + setNextButtonAsDefault(); + } else if (id == WizardCommon::Page_ServerSetup) { + if constexpr (Theme::doNotUseProxy()) { + setButtonLayout({QWizard::BackButton, QWizard::Stretch, QWizard::NextButton}); + } else { + setButtonLayout({QWizard::BackButton, QWizard::Stretch, QWizard::CustomButton3, QWizard::NextButton}); + } setNextButtonAsDefault(); } else { - setButtonLayout({ QWizard::BackButton, QWizard::Stretch, QWizard::NextButton }); + setButtonLayout({QWizard::BackButton, QWizard::Stretch, QWizard::NextButton}); setNextButtonAsDefault(); } diff --git a/src/gui/wizard/owncloudwizard.h b/src/gui/wizard/owncloudwizard.h index 5737e7d5af..c84840854f 100644 --- a/src/gui/wizard/owncloudwizard.h +++ b/src/gui/wizard/owncloudwizard.h @@ -15,6 +15,7 @@ #include "libsync/configfile.h" #include "networkjobs.h" #include "wizard/owncloudwizardcommon.h" +#include "wizard/wizardproxysettingsdialog.h" #include "accountfwd.h" namespace OCC { @@ -94,7 +95,7 @@ public slots: signals: void clearPendingRequests(); - void determineAuthType(const QString &); + void determineAuthType(const QUrl &serverURL, const OCC::WizardProxySettingsDialog::WizardProxySettings &proxySettings); void connectToOCUrl(const QString &); void createLocalAndRemoteFolders(const QString &, const QString &); // make sure to connect to this, rather than finished(int)!! @@ -115,6 +116,8 @@ private: [[nodiscard]] QSize calculateLargestSizeOfWizardPages(const QList &pageSizes) const; [[nodiscard]] QList calculateWizardPageSizes() const; + void ensureWelcomePageCorrectLayout(); + AccountPtr _account; WelcomePage *_welcomePage = nullptr; OwncloudSetupPage *_setupPage = nullptr; diff --git a/src/gui/wizard/proxysettings.ui b/src/gui/wizard/proxysettings.ui new file mode 100644 index 0000000000..292e4451f7 --- /dev/null +++ b/src/gui/wizard/proxysettings.ui @@ -0,0 +1,284 @@ + + + ProxySettings + + + + 0 + 0 + 481 + 296 + + + + Form + + + + + + true + + + + 0 + 0 + + + + Proxy Settings + + + + + + Manually specify proxy + + + + + + + + + true + + + + 0 + 0 + + + + + 0 + + + + + + + true + + + + 0 + 0 + + + + + + + + Qt::Orientation::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Host + + + + + + + + 1 + 0 + + + + + + + + + + + : + + + + + + + + 0 + 0 + + + + 1 + + + 65535 + + + 8080 + + + + + + + + + false + + + Proxy server requires authentication + + + + + + + true + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + false + + + + 1 + 0 + + + + + + + + + + + false + + + + 1 + 0 + + + + + + + QLineEdit::EchoMode::Password + + + + + + + + + + Note: proxy settings have no effects for accounts on localhost + + + + + + + + + + Qt::Orientation::Horizontal + + + + 40 + 20 + + + + + + + + + + Use system proxy + + + + + + + No proxy + + + true + + + + + + + Qt::Orientation::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Orientation::Vertical + + + + 20 + 40 + + + + + + + + + + + QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok + + + + + + + + diff --git a/src/gui/wizard/proxysettings.ui.license b/src/gui/wizard/proxysettings.ui.license new file mode 100644 index 0000000000..7be3270ab4 --- /dev/null +++ b/src/gui/wizard/proxysettings.ui.license @@ -0,0 +1,2 @@ +SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors +SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/gui/wizard/wizardproxysettingsdialog.cpp b/src/gui/wizard/wizardproxysettingsdialog.cpp new file mode 100644 index 0000000000..241ae5a868 --- /dev/null +++ b/src/gui/wizard/wizardproxysettingsdialog.cpp @@ -0,0 +1,208 @@ +/* + * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "wizardproxysettingsdialog.h" + +#include +#include + +namespace OCC { + +Q_LOGGING_CATEGORY(lcWizardProxySettings, "nextcloud.gui.wizard.proxysettings", QtInfoMsg) + +WizardProxySettingsDialog::WizardProxySettingsDialog(QUrl serverURL, + WizardProxySettings proxySettings, + QWidget *parent) + : QDialog(parent) +{ + _ui.setupUi(this); + + setWindowModality(Qt::WindowModal); + setWindowTitle(tr("Proxy Settings", "Dialog window title for proxy settings")); + + _ui.hostLineEdit->setPlaceholderText(tr("Hostname of proxy server")); + _ui.userLineEdit->setPlaceholderText(tr("Username for proxy server")); + _ui.passwordLineEdit->setPlaceholderText(tr("Password for proxy server")); + + _ui.typeComboBox->addItem(tr("HTTP(S) proxy"), QNetworkProxy::HttpProxy); + _ui.typeComboBox->addItem(tr("SOCKS5 proxy"), QNetworkProxy::Socks5Proxy); + + _ui.authRequiredcheckBox->setEnabled(true); + + // Explicitly set up the enabled status of the proxy auth widgets to ensure + // toggling the parent enables/disables the children + _ui.userLineEdit->setEnabled(true); + _ui.passwordLineEdit->setEnabled(true); + _ui.authWidgets->setEnabled(_ui.authRequiredcheckBox->isChecked()); + connect(_ui.authRequiredcheckBox, &QAbstractButton::toggled, _ui.authWidgets, &QWidget::setEnabled); + + connect(_ui.manualProxyRadioButton, &QAbstractButton::toggled, _ui.manualSettings, &QWidget::setVisible); + connect(_ui.manualProxyRadioButton, &QAbstractButton::toggled, this, &WizardProxySettingsDialog::validateProxySettings); + + connect(_ui.typeComboBox, static_cast(&QComboBox::currentIndexChanged), this, &WizardProxySettingsDialog::validateProxySettings); + connect(_ui.authRequiredcheckBox, &QAbstractButton::toggled, this, &WizardProxySettingsDialog::validateProxySettings); + + // Warn about empty proxy host + connect(_ui.hostLineEdit, &QLineEdit::textChanged, this, &WizardProxySettingsDialog::validateProxySettings); + connect(_ui.userLineEdit, &QLineEdit::textChanged, this, &WizardProxySettingsDialog::validateProxySettings); + connect(_ui.passwordLineEdit, &QLineEdit::textChanged, this, &WizardProxySettingsDialog::validateProxySettings); + connect(_ui.portSpinBox, &QSpinBox::valueChanged, this, &WizardProxySettingsDialog::validateProxySettings); + connect(_ui.authRequiredcheckBox, &QAbstractButton::toggled, this, &WizardProxySettingsDialog::validateProxySettings); + + connect(_ui.buttonBox, &QDialogButtonBox::accepted, + this, &WizardProxySettingsDialog::settingsDone); + connect(_ui.buttonBox, &QDialogButtonBox::rejected, + this, &WizardProxySettingsDialog::reject); + + setServerUrl(std::move(serverURL)); + setProxySettings(std::move(proxySettings)); +} + +void WizardProxySettingsDialog::setServerUrl(QUrl serverUrl) +{ + if (_serverURL == serverUrl) { + return; + } + + _serverURL = std::move(serverUrl); + checkAccountLocalhost(); +} + +void WizardProxySettingsDialog::setProxySettings(WizardProxySettings proxySettings) +{ + if (_settings == proxySettings) { + return; + } + + _settings = std::move(proxySettings); + + if (!_settings._user.isEmpty()) { + _ui.userLineEdit->setText(_settings._user); + } + if (!_settings._password.isEmpty()) { + _ui.passwordLineEdit->setText(_settings._password); + } + if (!_settings._host.isEmpty()) { + _ui.hostLineEdit->setText(_settings._host); + } + + _ui.authRequiredcheckBox->setChecked(_settings._needsAuth != ProxyAuthentication::NoAuthentication); + + switch (_settings._proxyType) + { + case QNetworkProxy::NoProxy: + _ui.noProxyRadioButton->setChecked(true); + _ui.noProxyRadioButton->setFocus(); + _ui.manualSettings->setVisible(false); + break; + case QNetworkProxy::ProxyType::DefaultProxy: + _ui.systemProxyRadioButton->setChecked(true); + _ui.systemProxyRadioButton->setFocus(); + _ui.manualSettings->setVisible(false); + break; + case QNetworkProxy::Socks5Proxy: + case QNetworkProxy::HttpProxy: + _ui.manualProxyRadioButton->setChecked(true); + _ui.manualProxyRadioButton->setFocus(); + _ui.manualSettings->setVisible(true); + break; + case QNetworkProxy::HttpCachingProxy: + case QNetworkProxy::FtpCachingProxy: + break; + } + + validateProxySettings(); +} + +void WizardProxySettingsDialog::checkEmptyProxyHost() +{ + if (_ui.hostLineEdit->isEnabled() && _ui.hostLineEdit->text().isEmpty()) { + _ui.hostLineEdit->setStyleSheet("border: 1px solid red"); + } else { + _ui.hostLineEdit->setStyleSheet(QString()); + } +} + +void WizardProxySettingsDialog::checkEmptyProxyCredentials() +{ + if (!_ui.authRequiredcheckBox->isChecked()) { + _ui.userLineEdit->setStyleSheet(QString()); + _ui.passwordLineEdit->setStyleSheet(QString()); + return; + } + + if (_ui.userLineEdit->text().isEmpty()) { + _ui.userLineEdit->setStyleSheet("border: 1px solid red"); + } else { + _ui.userLineEdit->setStyleSheet(QString()); + } + + if (_ui.passwordLineEdit->text().isEmpty()) { + _ui.passwordLineEdit->setStyleSheet("border: 1px solid red"); + } else { + _ui.passwordLineEdit->setStyleSheet(QString()); + } +} + +void WizardProxySettingsDialog::checkAccountLocalhost() +{ + auto visible = false; + if (_ui.manualProxyRadioButton->isChecked()) { + const auto host = _serverURL.host(); + // Some typical url for localhost + if (host == "localhost" || host.startsWith("127.") || host == "[::1]") { + visible = true; + } + } + _ui.labelLocalhost->setVisible(visible); +} + +void WizardProxySettingsDialog::validateProxySettings() +{ + checkEmptyProxyHost(); + checkEmptyProxyCredentials(); + checkAccountLocalhost(); + + _settings._user = _ui.userLineEdit->text(); + _settings._password = _ui.passwordLineEdit->text(); + _settings._host = _ui.hostLineEdit->text(); + _settings._port = _ui.portSpinBox->value(); + _settings._needsAuth = _ui.authRequiredcheckBox->isChecked() ? ProxyAuthentication::AuthenticationRequired : ProxyAuthentication::NoAuthentication; + + _settings._proxyType = QNetworkProxy::NoProxy; + _valid = false; + + if (_ui.noProxyRadioButton->isChecked()) { + _settings._proxyType = QNetworkProxy::NoProxy; + _valid = true; + } else if (_ui.systemProxyRadioButton->isChecked()) { + _settings._proxyType = QNetworkProxy::DefaultProxy; + _valid = true; + } else if (_ui.manualProxyRadioButton->isChecked()) { + _settings._proxyType = _ui.typeComboBox->itemData(_ui.typeComboBox->currentIndex()).value(); + _valid = true; + if (_settings._host.isEmpty()) { + _settings._proxyType = QNetworkProxy::NoProxy; + _valid = false; + } + if (_ui.authRequiredcheckBox->isChecked() && (_settings._user.isEmpty() || _settings._password.isEmpty())) { + _settings._proxyType = QNetworkProxy::NoProxy; + _valid = false; + } + } + + const auto okButton = _ui.buttonBox->button(QDialogButtonBox::Ok); + if (okButton) { + okButton->setEnabled(_valid); + } +} + +void WizardProxySettingsDialog::settingsDone() +{ + Q_EMIT proxySettingsAccepted(_settings); + accept(); +} + +} diff --git a/src/gui/wizard/wizardproxysettingsdialog.h b/src/gui/wizard/wizardproxysettingsdialog.h new file mode 100644 index 0000000000..01dd921369 --- /dev/null +++ b/src/gui/wizard/wizardproxysettingsdialog.h @@ -0,0 +1,69 @@ +/* + * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#pragma once + +#include +#include + +#include "ui_proxysettings.h" + +namespace OCC { + +class WizardProxySettingsDialog : public QDialog +{ + Q_OBJECT +public: + enum class ProxyAuthentication { + AuthenticationRequired, + NoAuthentication, + }; + + struct WizardProxySettings + { + QString _user; + QString _password; + QString _host; + quint16 _port; + ProxyAuthentication _needsAuth = ProxyAuthentication::NoAuthentication; + QNetworkProxy::ProxyType _proxyType = QNetworkProxy::NoProxy; + + bool operator == (const WizardProxySettings &other) const = default; + }; + + explicit WizardProxySettingsDialog(QUrl serverURL, + WizardProxySettings proxySettings, + QWidget *parent = nullptr); + + void setServerUrl(QUrl serverUrl); + + void setProxySettings(WizardProxySettings proxySettings); + +Q_SIGNALS: + void proxySettingsAccepted(const OCC::WizardProxySettingsDialog::WizardProxySettings &proxySettings); + +private Q_SLOTS: + /// Red marking of host field if empty and enabled + void checkEmptyProxyHost(); + + void checkEmptyProxyCredentials(); + + void checkAccountLocalhost(); + + void validateProxySettings(); + + void settingsDone(); + +private: + Ui_ProxySettings _ui{}; + + QUrl _serverURL; + + bool _valid = false; + + WizardProxySettings _settings; +}; + +} diff --git a/src/libsync/theme.cpp b/src/libsync/theme.cpp index cf7271963d..b93a688107 100644 --- a/src/libsync/theme.cpp +++ b/src/libsync/theme.cpp @@ -5,7 +5,6 @@ */ #include "theme.h" -#include "config.h" #include "common/utility.h" #include "version.h" #include "configfile.h" @@ -505,14 +504,7 @@ bool Theme::forbidBadSSL() const #endif } -bool Theme::doNotUseProxy() const -{ -#ifdef DO_NOT_USE_PROXY - return true; -#else - return false; -#endif -} + QString Theme::forceConfigAuthType() const { diff --git a/src/libsync/theme.h b/src/libsync/theme.h index 53d9df3b50..e2abad23cb 100644 --- a/src/libsync/theme.h +++ b/src/libsync/theme.h @@ -7,11 +7,14 @@ #ifndef _THEME_H #define _THEME_H +#include "config.h" + +#include "syncresult.h" + #include #include #include #include -#include "syncresult.h" class QString; class QObject; @@ -275,7 +278,10 @@ public: * * When true, the app always connects to the server directly */ - [[nodiscard]] bool doNotUseProxy() const; + [[nodiscard]] constexpr static bool doNotUseProxy() + { + return DO_NOT_USE_PROXY; + } /** * This is only useful when previous version had a different overrideServerUrl