Merge pull request #8623 from nextcloud/feat/proxySettingsNewAccountWizard

feat(wizard): allow to set proxy settings when setting up a new account
This commit is contained in:
Matthieu Gallien 2025-08-26 14:03:40 +02:00 committed by GitHub
commit e0a2217af3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 737 additions and 63 deletions

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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();

View File

@ -36,10 +36,10 @@
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
<enum>QSizePolicy::Policy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
@ -57,7 +57,7 @@
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
@ -77,7 +77,7 @@
<item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
@ -92,10 +92,10 @@
<item>
<spacer name="verticalSpacer_5">
<property name="orientation">
<enum>Qt::Vertical</enum>
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Minimum</enum>
<enum>QSizePolicy::Policy::Minimum</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
@ -129,7 +129,7 @@
<number>0</number>
</property>
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
<enum>QLayout::SizeConstraint::SetDefaultConstraint</enum>
</property>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
@ -139,10 +139,10 @@
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Minimum</enum>
<enum>QSizePolicy::Policy::Minimum</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
@ -160,7 +160,7 @@
<item>
<spacer name="horizontalSpacer_7">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
@ -175,7 +175,6 @@
<property name="font">
<font>
<pointsize>12</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
@ -187,7 +186,7 @@
<item>
<spacer name="horizontalSpacer_8">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
@ -210,10 +209,10 @@
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
<enum>QSizePolicy::Policy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
@ -262,7 +261,7 @@
<string>This is the link to your %1 web interface when you open it in the browser.</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
<set>Qt::AlignmentFlag::AlignCenter</set>
</property>
<property name="wordWrap">
<bool>true</bool>
@ -274,10 +273,10 @@
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
<enum>QSizePolicy::Policy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
@ -301,7 +300,7 @@
<string notr="true">Error Label</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
<enum>Qt::TextFormat::RichText</enum>
</property>
<property name="openExternalLinks">
<bool>true</bool>
@ -314,10 +313,10 @@
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::MinimumExpanding</enum>
<enum>QSizePolicy::Policy::MinimumExpanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
@ -337,10 +336,10 @@
<item>
<spacer name="verticalSpacer_4">
<property name="orientation">
<enum>Qt::Vertical</enum>
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::MinimumExpanding</enum>
<enum>QSizePolicy::Policy::MinimumExpanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>

View File

@ -18,13 +18,14 @@
#include <QBuffer>
#include <QJsonArray>
#include <QJsonDocument>
#include <QMetaObject>
#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<QAbstractButton *>(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,

View File

@ -9,16 +9,13 @@
#include <QWizard>
#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();
};

View File

@ -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<QSize> OwncloudWizard::calculateWizardPageSizes() const
return pageSizes;
}
void OwncloudWizard::ensureWelcomePageCorrectLayout()
{
setButtonLayout({QWizard::NextButton});
button(QWizard::NextButton)->setHidden(true);
}
QSize OwncloudWizard::calculateLargestSizeOfWizardPages(const QList<QSize> &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();
}

View File

@ -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<QSize> &pageSizes) const;
[[nodiscard]] QList<QSize> calculateWizardPageSizes() const;
void ensureWelcomePageCorrectLayout();
AccountPtr _account;
WelcomePage *_welcomePage = nullptr;
OwncloudSetupPage *_setupPage = nullptr;

View File

@ -0,0 +1,284 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ProxySettings</class>
<widget class="QWidget" name="ProxySettings">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>481</width>
<height>296</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QGroupBox" name="proxyGroupBox">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Proxy Settings</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="2" column="0">
<widget class="QRadioButton" name="manualProxyRadioButton">
<property name="text">
<string>Manually specify proxy</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="3">
<layout class="QHBoxLayout" name="horizontalLayout_9">
<item>
<widget class="QWidget" name="manualSettings" native="true">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="rightMargin">
<number>0</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_10">
<item>
<widget class="QComboBox" name="typeComboBox">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_5">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="hostLabel">
<property name="text">
<string>Host</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="hostLineEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string notr="true">:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="portSpinBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>65535</number>
</property>
<property name="value">
<number>8080</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="authRequiredcheckBox">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Proxy server requires authentication</string>
</property>
</widget>
</item>
<item>
<widget class="QWidget" name="authWidgets" native="true">
<property name="enabled">
<bool>true</bool>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLineEdit" name="userLineEdit">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="passwordLineEdit">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
<property name="echoMode">
<enum>QLineEdit::EchoMode::Password</enum>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QLabel" name="labelLocalhost">
<property name="text">
<string>Note: proxy settings have no effects for accounts on localhost</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_6">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QRadioButton" name="systemProxyRadioButton">
<property name="text">
<string>Use system proxy</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QRadioButton" name="noProxyRadioButton">
<property name="text">
<string>No proxy</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="2">
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="4" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item row="1" column="0">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,2 @@
SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
SPDX-License-Identifier: GPL-2.0-or-later

View File

@ -0,0 +1,208 @@
/*
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "wizardproxysettingsdialog.h"
#include <QPushButton>
#include <QLoggingCategory>
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<void (QComboBox::*)(int)>(&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<QNetworkProxy::ProxyType>();
_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();
}
}

View File

@ -0,0 +1,69 @@
/*
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include <QDialog>
#include <QNetworkProxy>
#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;
};
}

View File

@ -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
{

View File

@ -7,11 +7,14 @@
#ifndef _THEME_H
#define _THEME_H
#include "config.h"
#include "syncresult.h"
#include <QIcon>
#include <QObject>
#include <QPalette>
#include <QGuiApplication>
#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