From 5738110cb632cb62a36783bbabcc03300db7ff0f Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Thu, 13 Jul 2017 11:27:02 +0200 Subject: [PATCH] OAuth2: Have a link to the browser in the owncloud UI When the browser is open, ad a link in the ui to re-open the browser. Issue #5893 --- src/gui/accountsettings.cpp | 22 +++++++++++++++++++--- src/gui/accountsettings.h | 2 +- src/gui/accountstate.cpp | 4 +++- src/gui/accountstate.h | 7 +++++-- src/gui/application.cpp | 3 ++- src/gui/creds/httpcredentialsgui.cpp | 3 +++ src/gui/creds/httpcredentialsgui.h | 9 +++++++++ src/gui/creds/oauth.cpp | 11 ++++++----- src/gui/creds/oauth.h | 2 ++ 9 files changed, 50 insertions(+), 13 deletions(-) diff --git a/src/gui/accountsettings.cpp b/src/gui/accountsettings.cpp index 6da34d590..51a6130a6 100644 --- a/src/gui/accountsettings.cpp +++ b/src/gui/accountsettings.cpp @@ -30,6 +30,7 @@ #include "accountmanager.h" #include "owncloudsetupwizard.h" #include "creds/abstractcredentials.h" +#include "creds/httpcredentialsgui.h" #include "tooltipupdater.h" #include "filesystem.h" @@ -180,8 +181,8 @@ AccountSettings::AccountSettings(AccountState *accountState, QWidget *parent) ui->connectLabel->setText(tr("No account configured.")); - connect(_accountState, SIGNAL(stateChanged(int)), SLOT(slotAccountStateChanged(int))); - slotAccountStateChanged(_accountState->state()); + connect(_accountState, &AccountState::stateChanged, this, &AccountSettings::slotAccountStateChanged); + slotAccountStateChanged(); connect(&_quotaInfo, SIGNAL(quotaUpdated(qint64, qint64)), this, SLOT(slotUpdateQuota(qint64, qint64))); @@ -622,8 +623,9 @@ void AccountSettings::slotUpdateQuota(qint64 total, qint64 used) } } -void AccountSettings::slotAccountStateChanged(int state) +void AccountSettings::slotAccountStateChanged() { + int state = _accountState ? _accountState->state() : AccountState::Disconnected; if (_accountState) { ui->sslButton->updateAccountState(_accountState); AccountPtr account = _accountState->account(); @@ -654,6 +656,20 @@ void AccountSettings::slotAccountStateChanged(int state) showConnectionLabel(tr("Server %1 is currently in maintenance mode.").arg(server)); } else if (state == AccountState::SignedOut) { showConnectionLabel(tr("Signed out from %1.").arg(serverWithUser)); + } else if (state == AccountState::AskingCredentials) { + QUrl url; + if (auto cred = qobject_cast(account->credentials())) { + connect(cred, &HttpCredentialsGui::authorisationLinkChanged, + this, &AccountSettings::slotAccountStateChanged, Qt::UniqueConnection); + url = cred->authorisationLink(); + } + if (url.isValid()) { + showConnectionLabel(tr("Obtaining authorization from the browser. " + "Click here to re-open the browser.") + .arg(url.toString(QUrl::FullyEncoded))); + } else { + showConnectionLabel(tr("Connecting to %1...").arg(serverWithUser)); + } } else { showConnectionLabel(tr("No connection to %1 at %2.") .arg(Utility::escape(Theme::instance()->appNameGUI()), server), diff --git a/src/gui/accountsettings.h b/src/gui/accountsettings.h index 3e45d7e4a..eaef07eb4 100644 --- a/src/gui/accountsettings.h +++ b/src/gui/accountsettings.h @@ -65,7 +65,7 @@ signals: public slots: void slotOpenOC(); void slotUpdateQuota(qint64, qint64); - void slotAccountStateChanged(int state); + void slotAccountStateChanged(); AccountState *accountsState() { return _accountState; } diff --git a/src/gui/accountstate.cpp b/src/gui/accountstate.cpp index d2025dde1..dbe998ce1 100644 --- a/src/gui/accountstate.cpp +++ b/src/gui/accountstate.cpp @@ -133,6 +133,8 @@ QString AccountState::stateString(State state) return tr("Network error"); case ConfigurationError: return tr("Configuration error"); + case AskingCredentials: + return tr("Asking Credentials"); } return tr("Unknown account state"); } @@ -307,7 +309,7 @@ void AccountState::slotInvalidCredentials() account()->credentials()->invalidateToken(); account()->credentials()->askFromUser(); - setState(ConfigurationError); + setState(AskingCredentials); _waitingForNewCredentials = true; } diff --git a/src/gui/accountstate.h b/src/gui/accountstate.h index 2333bcece..ce36c94fb 100644 --- a/src/gui/accountstate.h +++ b/src/gui/accountstate.h @@ -64,8 +64,11 @@ public: /// again automatically. NetworkError, - /// An error like invalid credentials where retrying won't help. - ConfigurationError + /// Server configuration error. (For example: unsupported version) + ConfigurationError, + + /// We are currently asking the user for credentials + AskingCredentials }; /// The actual current connectivity status. diff --git a/src/gui/application.cpp b/src/gui/application.cpp index 2cb11ae30..3ebbb8fc5 100644 --- a/src/gui/application.cpp +++ b/src/gui/application.cpp @@ -308,7 +308,8 @@ void Application::slotCheckConnection() // Don't check if we're manually signed out or // when the error is permanent. if (state != AccountState::SignedOut - && state != AccountState::ConfigurationError) { + && state != AccountState::ConfigurationError + && state != AccountState::AskingCredentials) { accountState->checkConnectivity(); } } diff --git a/src/gui/creds/httpcredentialsgui.cpp b/src/gui/creds/httpcredentialsgui.cpp index 9c629ce65..dbc1c7e18 100644 --- a/src/gui/creds/httpcredentialsgui.cpp +++ b/src/gui/creds/httpcredentialsgui.cpp @@ -42,7 +42,10 @@ void HttpCredentialsGui::askFromUser() _asyncAuth.reset(new OAuth(_account, this)); connect(_asyncAuth.data(), &OAuth::result, this, &HttpCredentialsGui::asyncAuthResult); + connect(_asyncAuth.data(), &OAuth::destroyed, + this, &HttpCredentialsGui::authorisationLinkChanged); _asyncAuth->start(); + emit authorisationLinkChanged(); } else if (reply->error() == QNetworkReply::AuthenticationRequiredError) { // Show the dialog // We will re-enter the event loop, so better wait the next iteration diff --git a/src/gui/creds/httpcredentialsgui.h b/src/gui/creds/httpcredentialsgui.h index 0eaeeee81..fefc4dd1d 100644 --- a/src/gui/creds/httpcredentialsgui.h +++ b/src/gui/creds/httpcredentialsgui.h @@ -49,12 +49,21 @@ public: * or call showDialog to ask the password */ Q_INVOKABLE void askFromUser() Q_DECL_OVERRIDE; + /** + * In case of oauth, return an URL to the link to open the browser. + * An invalid URL otherwise + */ + QUrl authorisationLink() const { return _asyncAuth ? _asyncAuth->authorisationLink() : QUrl(); } + static QString requestAppPasswordText(const Account *account); private slots: void asyncAuthResult(OAuth::Result, const QString &user, const QString &accessToken, const QString &refreshToken); void showDialog(); +signals: + void authorisationLinkChanged(); + private: QScopedPointer> _asyncAuth; }; diff --git a/src/gui/creds/oauth.cpp b/src/gui/creds/oauth.cpp index 710e190ac..43133f91f 100644 --- a/src/gui/creds/oauth.cpp +++ b/src/gui/creds/oauth.cpp @@ -131,17 +131,18 @@ void OAuth::start() QTimer::singleShot(5 * 60 * 1000, this, [this] { result(Error); }); } - -bool OAuth::openBrowser() +QUrl OAuth::authorisationLink() const { Q_ASSERT(_server.isListening()); - auto url = QUrl(_account->url().toString() + return QUrl(_account->url().toString() + QLatin1String("/index.php/apps/oauth2/authorize?response_type=code&client_id=") + Theme::instance()->oauthClientId() + QLatin1String("&redirect_uri=http://localhost:") + QString::number(_server.serverPort())); +} - - if (!QDesktopServices::openUrl(url)) { +bool OAuth::openBrowser() +{ + if (!QDesktopServices::openUrl(authorisationLink())) { // We cannot open the browser, then we claim we don't support OAuth. emit result(NotSupported, QString()); return false; diff --git a/src/gui/creds/oauth.h b/src/gui/creds/oauth.h index fe7fd1c40..943f294f0 100644 --- a/src/gui/creds/oauth.h +++ b/src/gui/creds/oauth.h @@ -15,6 +15,7 @@ #pragma once #include #include +#include namespace OCC { @@ -53,6 +54,7 @@ public: Q_ENUM(Result); void start(); bool openBrowser(); + QUrl authorisationLink() const; signals: /**