From 736d2c31bfe704506d4c51a15a9ad5aaa8dfc9f9 Mon Sep 17 00:00:00 2001 From: Matthieu Gallien Date: Tue, 22 Oct 2024 14:49:51 +0200 Subject: [PATCH 1/2] content access denied error during discovery: verify server access will trigger a check of the server connectivity in case of content access denied reporting when listing folders during discovery should allow discovering early that terms of service need to be signed Signed-off-by: Matthieu Gallien --- src/gui/accountstate.cpp | 15 ++++-- src/gui/accountstate.h | 1 + src/gui/connectionvalidator.cpp | 91 ++++++++++++++++++++++++--------- src/gui/connectionvalidator.h | 38 +++++++++++++- 4 files changed, 117 insertions(+), 28 deletions(-) diff --git a/src/gui/accountstate.cpp b/src/gui/accountstate.cpp index 59f26fe7cc54..0e58b7c5ae84 100644 --- a/src/gui/accountstate.cpp +++ b/src/gui/accountstate.cpp @@ -48,6 +48,7 @@ AccountState::AccountState(const AccountPtr &account) , _state(AccountState::Disconnected) , _connectionStatus(ConnectionValidator::Undefined) , _waitingForNewCredentials(false) + , _termsOfServiceChecker(_account) , _maintenanceToConnectedDelay(60000 + (QRandomGenerator::global()->generate() % (4 * 60000))) // 1-5min delay , _remoteWipe(new RemoteWipe(_account)) , _isDesktopNotificationsAllowed(true) @@ -64,10 +65,18 @@ AccountState::AccountState(const AccountPtr &account) this, &AccountState::slotPushNotificationsReady); connect(account.data(), &Account::serverUserStatusChanged, this, &AccountState::slotServerUserStatusChanged); + connect(&_termsOfServiceChecker, &TermsOfServiceChecker::done, + this, [this] () + { + if (_termsOfServiceChecker.needToSign()) { + slotConnectionValidatorResult(ConnectionValidator::NeedToSignTermsOfService, {}); + } + }); connect(account.data(), &Account::termsOfServiceNeedToBeChecked, - this, [this] () { - checkConnectivity(); - }); + this, [this] () + { + _termsOfServiceChecker.start(); + }); connect(this, &AccountState::isConnectedChanged, [=]{ // Get the Apps available on the server if we're now connected. diff --git a/src/gui/accountstate.h b/src/gui/accountstate.h index 019b96d70cfd..fb306545c367 100644 --- a/src/gui/accountstate.h +++ b/src/gui/accountstate.h @@ -227,6 +227,7 @@ private Q_SLOTS: bool _waitingForNewCredentials = false; QDateTime _timeOfLastETagCheck; QPointer _connectionValidator; + TermsOfServiceChecker _termsOfServiceChecker; QByteArray _notificationsEtagResponseHeader; QByteArray _navigationAppsEtagResponseHeader; diff --git a/src/gui/connectionvalidator.cpp b/src/gui/connectionvalidator.cpp index 3d7c974df0ae..c5ed581db05b 100644 --- a/src/gui/connectionvalidator.cpp +++ b/src/gui/connectionvalidator.cpp @@ -42,7 +42,10 @@ ConnectionValidator::ConnectionValidator(AccountStatePtr accountState, const QSt , _previousErrors(previousErrors) , _accountState(accountState) , _account(accountState->account()) + , _termsOfServiceChecker(_account) { + connect(&_termsOfServiceChecker, &TermsOfServiceChecker::done, + this, &ConnectionValidator::termsOfServiceCheckDone); } void ConnectionValidator::checkServerAndAuth() @@ -270,19 +273,6 @@ void ConnectionValidator::slotCapabilitiesRecieved(const QJsonDocument &json) checkServerTermsOfService(); } -void ConnectionValidator::checkServerTermsOfService() -{ - // The main flow now needs the capabilities - auto *job = new JsonApiJob(_account, QLatin1String("ocs/v2.php/apps/terms_of_service/terms"), this); - job->setTimeout(timeoutToUseMsec); - QObject::connect(job, &JsonApiJob::jsonReceived, this, &ConnectionValidator::slotServerTermsOfServiceRecieved); - QObject::connect(job, &JsonApiJob::networkError, this, [] (QNetworkReply *reply) - { - qCInfo(lcConnectionValidator()) << "network error" << reply->error(); - }); - job->start(); -} - void ConnectionValidator::fetchUser() { auto *userInfo = new UserInfo(_accountState.data(), true, true, this); @@ -317,6 +307,11 @@ bool ConnectionValidator::setAndCheckServerVersion(const QString &version) return true; } +void ConnectionValidator::checkServerTermsOfService() +{ + _termsOfServiceChecker.start(); +} + void ConnectionValidator::slotUserFetched(UserInfo *userInfo) { if(userInfo) { @@ -332,17 +327,11 @@ void ConnectionValidator::slotUserFetched(UserInfo *userInfo) #endif } -void ConnectionValidator::slotServerTermsOfServiceRecieved(const QJsonDocument &reply) +void ConnectionValidator::termsOfServiceCheckDone() { - qCDebug(lcConnectionValidator) << "Terms of service status" << reply; - - if (reply.object().contains("ocs")) { - const auto hasSigned = reply.object().value("ocs").toObject().value("data").toObject().value("hasSigned").toBool(false); - - if (!hasSigned) { - reportResult(NeedToSignTermsOfService); - return; - } + if (_termsOfServiceChecker.needToSign()) { + reportResult(NeedToSignTermsOfService); + return; } fetchUser(); @@ -366,4 +355,60 @@ void ConnectionValidator::reportResult(Status status) deleteLater(); } +TermsOfServiceChecker::TermsOfServiceChecker(AccountPtr account, QObject *parent) + : QObject(parent) + , _account(account) +{ +} + +TermsOfServiceChecker::TermsOfServiceChecker(QObject *parent) + : QObject(parent) +{ +} + +bool TermsOfServiceChecker::needToSign() const +{ + return _needToSign; +} + +void TermsOfServiceChecker::start() +{ + checkServerTermsOfService(); +} + +void TermsOfServiceChecker::slotServerTermsOfServiceRecieved(const QJsonDocument &reply) +{ + qCDebug(lcConnectionValidator) << "Terms of service status" << reply; + + if (reply.object().contains("ocs")) { + const auto needToSign = !reply.object().value("ocs").toObject().value("data").toObject().value("hasSigned").toBool(false); + if (needToSign != _needToSign) { + _needToSign = needToSign; + emit needToSignChanged(); + } + } else if (_needToSign) { + _needToSign = false; + emit needToSignChanged(); + } + + emit done(); +} + +void TermsOfServiceChecker::checkServerTermsOfService() +{ + if (!_account) { + emit done(); + } + + // The main flow now needs the capabilities + auto *job = new JsonApiJob(_account, QLatin1String("ocs/v2.php/apps/terms_of_service/terms"), this); + job->setTimeout(timeoutToUseMsec); + QObject::connect(job, &JsonApiJob::jsonReceived, this, &TermsOfServiceChecker::slotServerTermsOfServiceRecieved); + QObject::connect(job, &JsonApiJob::networkError, this, [] (QNetworkReply *reply) + { + qCInfo(lcConnectionValidator()) << "network error" << reply->error(); + }); + job->start(); +} + } // namespace OCC diff --git a/src/gui/connectionvalidator.h b/src/gui/connectionvalidator.h index 788a30da2b81..0fc2c4c415bd 100644 --- a/src/gui/connectionvalidator.h +++ b/src/gui/connectionvalidator.h @@ -75,6 +75,37 @@ namespace OCC { class UserInfo; +class TermsOfServiceChecker : public QObject +{ + Q_OBJECT + + Q_PROPERTY(bool needToSign READ needToSign NOTIFY needToSignChanged FINAL) +public: + explicit TermsOfServiceChecker(AccountPtr account, + QObject *parent = nullptr); + + explicit TermsOfServiceChecker(QObject *parent = nullptr); + + [[nodiscard]] bool needToSign() const; + +public slots: + void start(); + +signals: + void needToSignChanged(); + + void done(); + +private slots: + void slotServerTermsOfServiceRecieved(const QJsonDocument &reply); + +private: + void checkServerTermsOfService(); + + AccountPtr _account; + bool _needToSign = false; +}; + class ConnectionValidator : public QObject { Q_OBJECT @@ -130,7 +161,8 @@ protected slots: void slotCapabilitiesRecieved(const QJsonDocument &); void slotUserFetched(OCC::UserInfo *userInfo); - void slotServerTermsOfServiceRecieved(const QJsonDocument &reply); + + void termsOfServiceCheckDone(); private: #ifndef TOKEN_AUTH_ONLY @@ -138,7 +170,6 @@ protected slots: #endif void reportResult(Status status); void checkServerCapabilities(); - void checkServerTermsOfService(); void fetchUser(); /** Sets the account's server version @@ -147,10 +178,13 @@ protected slots: */ bool setAndCheckServerVersion(const QString &version); + void checkServerTermsOfService(); + const QStringList _previousErrors; QStringList _errors; AccountStatePtr _accountState; AccountPtr _account; + TermsOfServiceChecker _termsOfServiceChecker; bool _isCheckingServerAndAuth = false; }; } From 25f9e16a7dc55cd49b1234c0ca86c605e7993441 Mon Sep 17 00:00:00 2001 From: Matthieu Gallien Date: Tue, 22 Oct 2024 17:13:31 +0200 Subject: [PATCH 2/2] notify user once when terms of service need to be signed Signed-off-by: Matthieu Gallien --- src/gui/accountstate.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/accountstate.cpp b/src/gui/accountstate.cpp index 0e58b7c5ae84..4548ab5595c7 100644 --- a/src/gui/accountstate.cpp +++ b/src/gui/accountstate.cpp @@ -362,7 +362,7 @@ void AccountState::slotConnectionValidatorResult(ConnectionValidator::Status sta _lastConnectionValidatorStatus = status; if ((_lastConnectionValidatorStatus == ConnectionValidator::NeedToSignTermsOfService && status == ConnectionValidator::Connected) || - status == ConnectionValidator::NeedToSignTermsOfService) { + (status == ConnectionValidator::NeedToSignTermsOfService && _lastConnectionValidatorStatus != status)) { emit termsOfServiceChanged(_account); }