Skip to content

Commit ebc37e2

Browse files
fix: OAuth: Prevent logout when refreshing token (#12005)
Prevent the user being logged out when the network disappears during OAuth token refresh. Co-authored-by: Erik Verbruggen <erik@verbruggen.consulting>
1 parent e04263d commit ebc37e2

File tree

1 file changed

+41
-19
lines changed

1 file changed

+41
-19
lines changed

src/libsync/creds/httpcredentials.cpp

+41-19
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <QJsonObject>
2828
#include <QLoggingCategory>
2929
#include <QMutex>
30+
#include <QNetworkInformation>
3031
#include <QNetworkReply>
3132

3233
#include <chrono>
@@ -37,6 +38,7 @@ Q_LOGGING_CATEGORY(lcHttpCredentials, "sync.credentials.http", QtInfoMsg)
3738

3839
namespace {
3940
constexpr int TokenRefreshMaxRetries = 3;
41+
constexpr std::chrono::seconds TokenRefreshDefaultTimeout = 30s;
4042
constexpr int CredentialVersion = 1;
4143
const char authenticationFailedC[] = "owncloud-authentication-failed";
4244

@@ -270,29 +272,47 @@ bool HttpCredentials::refreshAccessTokenInternal(int tokenRefreshRetriesCount)
270272
_oAuthJob = new AccountBasedOAuth(_account->sharedFromThis(), _account->accessManager());
271273
connect(_oAuthJob, &AccountBasedOAuth::refreshError, this, [tokenRefreshRetriesCount, this](QNetworkReply::NetworkError error, const QString &) {
272274
_oAuthJob->deleteLater();
275+
276+
auto networkUnavailable = []() {
277+
if (auto qni = QNetworkInformation::instance()) {
278+
if (qni->reachability() == QNetworkInformation::Reachability::Disconnected) {
279+
return true;
280+
}
281+
}
282+
283+
return false;
284+
};
285+
273286
int nextTry = tokenRefreshRetriesCount + 1;
274287
std::chrono::seconds timeout = {};
275-
switch (error) {
276-
case QNetworkReply::ContentNotFoundError:
277-
// 404: bigip f5?
278-
timeout = 0s;
279-
break;
280-
case QNetworkReply::HostNotFoundError:
281-
[[fallthrough]];
282-
case QNetworkReply::TimeoutError:
283-
[[fallthrough]];
284-
// Qt reports OperationCanceledError if the request timed out
285-
case QNetworkReply::OperationCanceledError:
286-
[[fallthrough]];
287-
case QNetworkReply::TemporaryNetworkFailureError:
288-
[[fallthrough]];
289-
// VPN not ready?
290-
case QNetworkReply::ConnectionRefusedError:
288+
289+
if (networkUnavailable()) {
291290
nextTry = 0;
292-
[[fallthrough]];
293-
default:
294-
timeout = 30s;
291+
timeout = TokenRefreshDefaultTimeout;
292+
} else {
293+
switch (error) {
294+
case QNetworkReply::ContentNotFoundError:
295+
// 404: bigip f5?
296+
timeout = 0s;
297+
break;
298+
case QNetworkReply::HostNotFoundError:
299+
[[fallthrough]];
300+
case QNetworkReply::TimeoutError:
301+
[[fallthrough]];
302+
// Qt reports OperationCanceledError if the request timed out
303+
case QNetworkReply::OperationCanceledError:
304+
[[fallthrough]];
305+
case QNetworkReply::TemporaryNetworkFailureError:
306+
[[fallthrough]];
307+
// VPN not ready?
308+
case QNetworkReply::ConnectionRefusedError:
309+
nextTry = 0;
310+
[[fallthrough]];
311+
default:
312+
timeout = TokenRefreshDefaultTimeout;
313+
}
295314
}
315+
296316
if (nextTry >= TokenRefreshMaxRetries) {
297317
qCWarning(lcHttpCredentials) << "Too many failed refreshes" << nextTry << "-> log out";
298318
forgetSensitiveData();
@@ -331,6 +351,8 @@ bool HttpCredentials::refreshAccessTokenInternal(int tokenRefreshRetriesCount)
331351

332352
void HttpCredentials::invalidateToken()
333353
{
354+
qCWarning(lcHttpCredentials) << "Invalidating the credentials";
355+
334356
if (!_password.isEmpty()) {
335357
_previousPassword = _password;
336358
}

0 commit comments

Comments
 (0)