Skip to content

Commit

Permalink
implement terms of service check wizard page
Browse files Browse the repository at this point in the history
this is only shown if the TOS haven't been accepted yet!

for now this only opens the browser, similar to the Flow2Auth page

the `TermsOfServiceCheckWidget` is a combination of the `Flow2Auth` and
the `Flow2AuthWidget` classes -- in the future we ideally display the
required TOS directly in the wizard

Signed-off-by: Jyrki Gadinger <nilsding@nilsding.org>
  • Loading branch information
nilsding committed Feb 18, 2025
1 parent f8f608d commit 12e8d96
Show file tree
Hide file tree
Showing 13 changed files with 608 additions and 56 deletions.
3 changes: 3 additions & 0 deletions src/gui/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ set(client_UI_SRCS
wizard/owncloudconnectionmethoddialog.ui
wizard/owncloudhttpcredspage.ui
wizard/owncloudsetupnocredspage.ui
wizard/termsofservicecheckwidget.ui
wizard/webview.ui
wizard/welcomepage.ui
)
Expand Down Expand Up @@ -240,6 +241,8 @@ set(client_SRCS
wizard/flow2authwidget.cpp
wizard/owncloudsetuppage.h
wizard/owncloudsetuppage.cpp
wizard/termsofservicecheckwidget.h
wizard/termsofservicecheckwidget.cpp
wizard/termsofservicewizardpage.h
wizard/termsofservicewizardpage.cpp
wizard/owncloudwizardcommon.h
Expand Down
51 changes: 15 additions & 36 deletions src/gui/owncloudsetupwizard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
#include "sslerrordialog.h"
#include "wizard/owncloudwizard.h"
#include "wizard/owncloudwizardcommon.h"
#include "connectionvalidator.h"

#include "creds/credentialsfactory.h"
#include "creds/abstractcredentials.h"
Expand Down Expand Up @@ -378,12 +377,20 @@ void OwncloudSetupWizard::testOwnCloudConnect()
job->setFollowRedirects(false);
job->setProperties(QList<QByteArray>() << "getlastmodified");
connect(job, &PropfindJob::result, _ocWizard, &OwncloudWizard::successfulStep);
connect(job, &PropfindJob::finishedWithError, this, [this] (QNetworkReply *reply) {
connect(job, &PropfindJob::finishedWithError, this, [this] (QNetworkReply *reply) -> void {
if (reply && reply->error() == QNetworkReply::ContentAccessDenied) {
testTermsOfService();
} else {
slotAuthError();
// A 403 might indicate that the terms of service need to be signed.
// catch this special case here, fall back to the standard error handler if it's not TOS-related
auto davException = OCC::getExceptionFromReply(reply);
if (!davException.first.isEmpty() && davException.first == QStringLiteral(R"(OCA\TermsOfService\TermsNotSignedException)")) {
// authentication was successful, but the user hasn't signed the terms of service yet. Prompt for that in the next step
qCInfo(lcWizard) << "Terms of service not accepted yet! Will prompt the user in the next step";
_ocWizard->_needsToAcceptTermsOfService = true;
_ocWizard->successfulStep();
return;
}
}
slotAuthError();
});

job->start();
Expand Down Expand Up @@ -422,34 +429,25 @@ void OwncloudSetupWizard::slotAuthError()
"\"%1\". The URL is bad, the server is misconfigured.")
.arg(Utility::escape(redirectUrl.toString()));

} else if (reply->error() == QNetworkReply::ContentNotFoundError) {
// A 404 is actually a success: we were authorized to know that the folder does
// not exist. It will be created later...
} else if (reply->error() == QNetworkReply::ContentAccessDenied) {
testTermsOfService();
return;
} else if (reply->error() == QNetworkReply::ContentNotFoundError) {
_ocWizard->successfulStep();
return;

// Provide messages for other errors, such as invalid credentials.
} else if (reply->error() != QNetworkReply::NoError) {
auto davException = OCC::getExceptionFromReply(reply);
// Provide messages for other errors, such as invalid credentials.

if (!_ocWizard->account()->credentials()->stillValid(reply)) {

Check warning on line 441 in src/gui/owncloudsetupwizard.cpp

View workflow job for this annotation

GitHub Actions / build

src/gui/owncloudsetupwizard.cpp:441:9 [bugprone-branch-clone]

if with identical then and else branches
errorMsg = tr("Access forbidden by server. To verify that you have proper access, "
"<a href=\"%1\">click here</a> to access the service with your browser.")
.arg(Utility::escape(_ocWizard->account()->url().toString()));
} else if (!davException.first.isEmpty() && davException.first == QStringLiteral(R"(OCA\TermsOfService\TermsNotSignedException)")) {
qCInfo(lcWizard) << "Terms of service not accepted yet!";
// TODO: it would be cool to display a new wizard page containing the terms of service
errorMsg = tr("Please accept the <a href=\"%1\">Terms of Service</a> with your browser and try again.")
.arg(Utility::escape(_ocWizard->account()->url().toString()));
} else {
errorMsg = job->errorStringParsingBody();
}

// Something else went wrong, maybe the response was 200 but with invalid data.
} else {
// Something else went wrong, maybe the response was 200 but with invalid data.
errorMsg = tr("There was an invalid response to an authenticated WebDAV request");
}

Expand Down Expand Up @@ -484,14 +482,6 @@ bool OwncloudSetupWizard::checkDowngradeAdvised(QNetworkReply *reply)
return true;
}

void OwncloudSetupWizard::testTermsOfService()
{
_termsOfServiceChecker = new TermsOfServiceChecker{_ocWizard->account(), this};

connect(_termsOfServiceChecker, &TermsOfServiceChecker::done, this, &OwncloudSetupWizard::termsOfServiceChecked);
_termsOfServiceChecker->start();
}

void OwncloudSetupWizard::slotCreateLocalAndRemoteFolders(const QString &localFolder, const QString &remoteFolder)
{
qCInfo(lcWizard) << "Setup local sync folder for new oC connection " << localFolder;
Expand Down Expand Up @@ -745,17 +735,6 @@ void OwncloudSetupWizard::slotSkipFolderConfiguration()
emit ownCloudWizardDone(QDialog::Accepted);
}

void OwncloudSetupWizard::termsOfServiceChecked()
{
if (_termsOfServiceChecker && _termsOfServiceChecker->needToSign()) {
QDesktopServices::openUrl(_ocWizard->account()->url());
} else {
_ocWizard->successfulStep();
delete _termsOfServiceChecker;
_termsOfServiceChecker = nullptr;
}
}

AccountState *OwncloudSetupWizard::applyAccountChanges()
{
AccountPtr newAccount = _ocWizard->account();
Expand Down
5 changes: 1 addition & 4 deletions src/gui/owncloudsetupwizard.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class OwncloudSetupWizard : public QObject
/** Run the wizard */
static void runWizard(QObject *obj, const char *amember, QWidget *parent = nullptr);
static bool bringWizardToFrontIfVisible();

signals:
// overall dialog close signal.
void ownCloudWizardDone(int);
Expand All @@ -70,8 +71,6 @@ private slots:
void slotAssistantFinished(int);
void slotSkipFolderConfiguration();

void termsOfServiceChecked();

private:
explicit OwncloudSetupWizard(QObject *parent = nullptr);
~OwncloudSetupWizard() override;
Expand All @@ -82,9 +81,7 @@ private slots:
bool ensureStartFromScratch(const QString &localFolder);
AccountState *applyAccountChanges();
bool checkDowngradeAdvised(QNetworkReply *reply);
void testTermsOfService();

TermsOfServiceChecker *_termsOfServiceChecker = nullptr;
OwncloudWizard *_ocWizard = nullptr;
QString _initLocalFolder;
QString _remoteFolder;
Expand Down
8 changes: 7 additions & 1 deletion src/gui/wizard/flow2authcredspage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,13 @@ void Flow2AuthCredsPage::slotFlow2AuthResult(Flow2Auth::Result r, const QString

int Flow2AuthCredsPage::nextId() const
{
return WizardCommon::Page_TermsOfService;
const auto ocWizard = qobject_cast<OwncloudWizard *>(wizard());
Q_ASSERT(ocWizard);
if (ocWizard->needsToAcceptTermsOfService()) {
return WizardCommon::Page_TermsOfService;
}

return WizardCommon::Page_AdvancedSetup;
}

void Flow2AuthCredsPage::setConnected()
Expand Down
6 changes: 6 additions & 0 deletions src/gui/wizard/owncloudhttpcredspage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,12 @@ bool OwncloudHttpCredsPage::validatePage()

int OwncloudHttpCredsPage::nextId() const
{
const auto ocWizard = qobject_cast<OwncloudWizard *>(wizard());
Q_ASSERT(ocWizard);
if (ocWizard->needsToAcceptTermsOfService()) {
return WizardCommon::Page_TermsOfService;
}

return WizardCommon::Page_AdvancedSetup;
}

Expand Down
16 changes: 14 additions & 2 deletions src/gui/wizard/owncloudwizard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ OwncloudWizard::OwncloudWizard(QWidget *parent)
, _setupPage(new OwncloudSetupPage(this))
, _httpCredsPage(new OwncloudHttpCredsPage(this))
, _flow2CredsPage(new Flow2AuthCredsPage)
, _termsOfServicePage(new TermsOfServiceWizardPage)
, _advancedSetupPage(new OwncloudAdvancedSetupPage(this))
#ifdef WITH_WEBENGINE
, _webViewPage(new WebViewPage(this))
Expand All @@ -72,6 +73,7 @@ OwncloudWizard::OwncloudWizard(QWidget *parent)
setPage(WizardCommon::Page_ServerSetup, _setupPage);
setPage(WizardCommon::Page_HttpCreds, _httpCredsPage);
setPage(WizardCommon::Page_Flow2AuthCreds, _flow2CredsPage);
setPage(WizardCommon::Page_TermsOfService, _termsOfServicePage);
setPage(WizardCommon::Page_AdvancedSetup, _advancedSetupPage);
#ifdef WITH_WEBENGINE
if (!useFlow2()) {
Expand Down Expand Up @@ -117,6 +119,7 @@ OwncloudWizard::OwncloudWizard(QWidget *parent)
connect(this, &OwncloudWizard::styleChanged, _setupPage, &OwncloudSetupPage::slotStyleChanged);
connect(this, &OwncloudWizard::styleChanged, _advancedSetupPage, &OwncloudAdvancedSetupPage::slotStyleChanged);
connect(this, &OwncloudWizard::styleChanged, _flow2CredsPage, &Flow2AuthCredsPage::slotStyleChanged);
connect(this, &OwncloudWizard::styleChanged, _termsOfServicePage, &TermsOfServiceWizardPage::styleChanged);

customizeStyle();

Expand Down Expand Up @@ -217,6 +220,11 @@ bool OwncloudWizard::isConfirmBigFolderChecked() const
return _advancedSetupPage->isConfirmBigFolderChecked();
}

bool OwncloudWizard::needsToAcceptTermsOfService() const
{
return _needsToAcceptTermsOfService;
}

QString OwncloudWizard::ocUrl() const
{
QString url = field("OCUrl").toString().simplified();
Expand Down Expand Up @@ -263,7 +271,7 @@ void OwncloudWizard::successfulStep()
#endif // WITH_WEBENGINE

case WizardCommon::Page_TermsOfService:
_termsOfServicePage->initializePage();
// nothing to do here
break;

case WizardCommon::Page_AdvancedSetup:
Expand Down Expand Up @@ -292,6 +300,9 @@ void OwncloudWizard::slotCustomButtonClicked(const int which)
} else if (which == WizardButton::CustomButton2) {
// Because QWizard doesn't have a way of directly going to a specific page (!!!)
restart();

// in case the wizard had been cancelled at a page where the need for signing the TOS got checked:
_needsToAcceptTermsOfService = false;
}
}

Expand Down Expand Up @@ -336,7 +347,8 @@ void OwncloudWizard::slotCurrentPageChanged(int id)
#ifdef WITH_WEBENGINE
id == WizardCommon::Page_WebView ||
#endif // WITH_WEBENGINE
id == WizardCommon::Page_Flow2AuthCreds) {
id == WizardCommon::Page_Flow2AuthCreds ||
id == WizardCommon::Page_TermsOfService) {
setButtonLayout({ QWizard::BackButton, QWizard::Stretch });
} else if (id == WizardCommon::Page_AdvancedSetup) {
setButtonLayout({ QWizard::CustomButton2, QWizard::Stretch, QWizard::CustomButton1, QWizard::FinishButton });
Expand Down
3 changes: 3 additions & 0 deletions src/gui/wizard/owncloudwizard.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ class OwncloudWizard : public QWizard
[[nodiscard]] bool useFlow2() const;
[[nodiscard]] bool useVirtualFileSync() const;
[[nodiscard]] bool isConfirmBigFolderChecked() const;
[[nodiscard]] bool needsToAcceptTermsOfService() const;

void displayError(const QString &, bool retryHTTPonly);
[[nodiscard]] AbstractCredentials *getCredentials() const;
Expand Down Expand Up @@ -140,6 +141,8 @@ public slots:

bool _useFlow2 = ConfigFile().forceLoginV2();

bool _needsToAcceptTermsOfService = false;

friend class OwncloudSetupWizard;
};

Expand Down
Loading

0 comments on commit 12e8d96

Please sign in to comment.