2013-05-04 18:01:45 +04:00
|
|
|
/*
|
|
|
|
* Copyright (C) by Klaas Freitag <freitag@owncloud.com>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
2016-10-25 12:00:07 +03:00
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
2013-05-04 18:01:45 +04:00
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful, but
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
|
|
* for more details.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <QtCore>
|
2013-10-21 23:42:52 +04:00
|
|
|
#include <QNetworkReply>
|
2015-03-24 23:30:42 +03:00
|
|
|
#include <QNetworkProxyFactory>
|
2017-01-22 15:55:08 +03:00
|
|
|
#include <QPixmap>
|
2013-05-04 18:01:45 +04:00
|
|
|
|
2014-07-11 02:31:24 +04:00
|
|
|
#include "connectionvalidator.h"
|
|
|
|
#include "account.h"
|
|
|
|
#include "networkjobs.h"
|
2015-03-24 23:30:42 +03:00
|
|
|
#include "clientproxy.h"
|
2014-03-03 20:55:15 +04:00
|
|
|
#include <creds/abstractcredentials.h>
|
2013-05-04 18:01:45 +04:00
|
|
|
|
2014-11-10 00:34:07 +03:00
|
|
|
namespace OCC {
|
2013-05-04 18:01:45 +04:00
|
|
|
|
2015-11-23 23:47:30 +03:00
|
|
|
// Make sure the timeout for this job is less than how often we get called
|
|
|
|
// This makes sure we get tried often enough without "ConnectionValidator already running"
|
2016-02-10 14:35:26 +03:00
|
|
|
static qint64 timeoutToUseMsec = qMax(1000, ConnectionValidator::DefaultCallingIntervalMsec - 5*1000);
|
2015-11-23 23:47:30 +03:00
|
|
|
|
2015-09-05 16:39:22 +03:00
|
|
|
ConnectionValidator::ConnectionValidator(AccountPtr account, QObject *parent)
|
2013-07-30 16:37:46 +04:00
|
|
|
: QObject(parent),
|
2015-02-05 17:18:38 +03:00
|
|
|
_account(account),
|
|
|
|
_isCheckingServerAndAuth(false)
|
2013-05-04 18:01:45 +04:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2014-12-11 15:55:59 +03:00
|
|
|
QString ConnectionValidator::statusString( Status stat )
|
2013-05-04 18:01:45 +04:00
|
|
|
{
|
2013-07-05 15:14:48 +04:00
|
|
|
switch( stat ) {
|
|
|
|
case Undefined:
|
2014-12-11 17:43:48 +03:00
|
|
|
return QLatin1String("Undefined");
|
2013-07-05 15:14:48 +04:00
|
|
|
case Connected:
|
2014-12-11 17:43:48 +03:00
|
|
|
return QLatin1String("Connected");
|
2013-07-05 15:14:48 +04:00
|
|
|
case NotConfigured:
|
2014-12-11 17:43:48 +03:00
|
|
|
return QLatin1String("NotConfigured");
|
2013-07-05 15:14:48 +04:00
|
|
|
case ServerVersionMismatch:
|
2014-12-11 17:43:48 +03:00
|
|
|
return QLatin1String("Server Version Mismatch");
|
2015-09-05 16:37:20 +03:00
|
|
|
case CredentialsMissingOrWrong:
|
2014-12-11 17:43:48 +03:00
|
|
|
return QLatin1String("Credentials Wrong");
|
2013-07-05 15:14:48 +04:00
|
|
|
case StatusNotFound:
|
2014-12-11 17:43:48 +03:00
|
|
|
return QLatin1String("Status not found");
|
2015-01-21 17:30:25 +03:00
|
|
|
case UserCanceledCredentials:
|
|
|
|
return QLatin1String("User canceled credentials");
|
2015-04-24 12:32:47 +03:00
|
|
|
case ServiceUnavailable:
|
|
|
|
return QLatin1String("Service unavailable");
|
2017-05-08 13:39:08 +03:00
|
|
|
case MaintenanceMode:
|
|
|
|
return QLatin1String("Maintenance mode");
|
2014-12-11 17:43:48 +03:00
|
|
|
case Timeout:
|
|
|
|
return QLatin1String("Timeout");
|
2013-07-05 15:14:48 +04:00
|
|
|
}
|
2014-12-11 17:43:48 +03:00
|
|
|
return QLatin1String("status undeclared.");
|
2013-05-04 18:01:45 +04:00
|
|
|
}
|
|
|
|
|
2014-12-17 16:09:57 +03:00
|
|
|
void ConnectionValidator::checkServerAndAuth()
|
2013-05-04 18:01:45 +04:00
|
|
|
{
|
2014-12-03 15:10:49 +03:00
|
|
|
if( !_account ) {
|
|
|
|
_errors << tr("No ownCloud account configured");
|
2014-12-11 15:55:59 +03:00
|
|
|
reportResult( NotConfigured );
|
2014-12-03 15:10:49 +03:00
|
|
|
return;
|
|
|
|
}
|
2015-03-27 13:53:58 +03:00
|
|
|
qDebug() << "Checking server and authentication";
|
|
|
|
|
2015-02-05 17:18:38 +03:00
|
|
|
_isCheckingServerAndAuth = true;
|
2014-12-03 15:10:49 +03:00
|
|
|
|
2015-03-24 23:30:42 +03:00
|
|
|
// Lookup system proxy in a thread https://github.com/owncloud/client/issues/2993
|
|
|
|
if (ClientProxy::isUsingSystemDefault()) {
|
|
|
|
qDebug() << "Trying to look up system proxy";
|
|
|
|
ClientProxy::lookupSystemProxyAsync(_account->url(),
|
|
|
|
this, SLOT(systemProxyLookupDone(QNetworkProxy)));
|
|
|
|
} else {
|
2015-03-25 14:25:18 +03:00
|
|
|
// We want to reset the QNAM proxy so that the global proxy settings are used (via ClientProxy settings)
|
|
|
|
_account->networkAccessManager()->setProxy(QNetworkProxy(QNetworkProxy::DefaultProxy));
|
2015-03-24 23:30:42 +03:00
|
|
|
// use a queued invocation so we're as asynchronous as with the other code path
|
|
|
|
QMetaObject::invokeMethod(this, "slotCheckServerAndAuth", Qt::QueuedConnection);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ConnectionValidator::systemProxyLookupDone(const QNetworkProxy &proxy) {
|
|
|
|
if (!_account) {
|
|
|
|
qDebug() << "Bailing out, Account had been deleted";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-11-17 13:02:15 +03:00
|
|
|
if (proxy.type() != QNetworkProxy::NoProxy) {
|
|
|
|
qDebug() << "Setting QNAM proxy to be system proxy" << printQNetworkProxy(proxy);
|
|
|
|
} else {
|
|
|
|
qDebug() << "No system proxy set by OS";
|
|
|
|
}
|
2015-03-27 13:53:58 +03:00
|
|
|
_account->networkAccessManager()->setProxy(proxy);
|
2015-03-24 23:30:42 +03:00
|
|
|
|
|
|
|
slotCheckServerAndAuth();
|
|
|
|
}
|
|
|
|
|
|
|
|
// The actual check
|
|
|
|
void ConnectionValidator::slotCheckServerAndAuth()
|
|
|
|
{
|
2014-12-17 16:09:57 +03:00
|
|
|
CheckServerJob *checkJob = new CheckServerJob(_account, this);
|
2015-11-23 23:47:30 +03:00
|
|
|
checkJob->setTimeout(timeoutToUseMsec);
|
2014-12-17 16:09:57 +03:00
|
|
|
checkJob->setIgnoreCredentialFailure(true);
|
2017-04-26 13:15:33 +03:00
|
|
|
connect(checkJob, SIGNAL(instanceFound(QUrl,QJsonObject)), SLOT(slotStatusFound(QUrl,QJsonObject)));
|
2016-09-20 12:55:43 +03:00
|
|
|
connect(checkJob, SIGNAL(instanceNotFound(QNetworkReply*)), SLOT(slotNoStatusFound(QNetworkReply*)));
|
2014-12-17 16:09:57 +03:00
|
|
|
connect(checkJob, SIGNAL(timeout(QUrl)), SLOT(slotJobTimeout(QUrl)));
|
|
|
|
checkJob->start();
|
2013-05-04 18:01:45 +04:00
|
|
|
}
|
|
|
|
|
2017-04-26 13:15:33 +03:00
|
|
|
void ConnectionValidator::slotStatusFound(const QUrl&url, const QJsonObject &info)
|
2013-05-04 18:01:45 +04:00
|
|
|
{
|
2017-04-19 12:02:03 +03:00
|
|
|
// Newer servers don't disclose any version in status.php anymore
|
|
|
|
// https://github.com/owncloud/core/pull/27473/files
|
|
|
|
// so this string can be empty.
|
|
|
|
QString serverVersion = CheckServerJob::version(info);
|
|
|
|
|
2013-05-04 18:01:45 +04:00
|
|
|
// status.php was found.
|
2013-10-23 16:48:44 +04:00
|
|
|
qDebug() << "** Application: ownCloud found: "
|
2013-10-28 23:01:59 +04:00
|
|
|
<< url << " with version "
|
2013-10-23 16:48:44 +04:00
|
|
|
<< CheckServerJob::versionString(info)
|
2017-04-19 12:02:03 +03:00
|
|
|
<< "(" << serverVersion << ")";
|
2015-02-12 14:59:00 +03:00
|
|
|
|
2017-04-19 12:02:03 +03:00
|
|
|
if (!serverVersion.isEmpty() && !setAndCheckServerVersion(serverVersion)) {
|
2013-05-04 18:01:45 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-05-08 13:39:08 +03:00
|
|
|
if (info["maintenance"].toBool()) {
|
|
|
|
reportResult( MaintenanceMode );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-12-03 15:10:49 +03:00
|
|
|
// now check the authentication
|
2015-09-05 16:37:20 +03:00
|
|
|
if (_account->credentials()->ready())
|
2014-12-17 16:09:57 +03:00
|
|
|
QTimer::singleShot( 0, this, SLOT( checkAuthentication() ));
|
2015-09-05 16:37:20 +03:00
|
|
|
else
|
|
|
|
reportResult( CredentialsMissingOrWrong );
|
2013-05-04 18:01:45 +04:00
|
|
|
}
|
|
|
|
|
2015-02-11 11:23:04 +03:00
|
|
|
// status.php could not be loaded (network or server issue!).
|
2013-10-28 23:01:59 +04:00
|
|
|
void ConnectionValidator::slotNoStatusFound(QNetworkReply *reply)
|
2013-05-04 18:01:45 +04:00
|
|
|
{
|
2017-03-23 17:53:22 +03:00
|
|
|
auto job = qobject_cast<CheckServerJob *>(sender());
|
|
|
|
qDebug() << Q_FUNC_INFO << reply->error() << job->errorString() << reply->peek(1024);
|
|
|
|
if (!_account->credentials()->ready()) {
|
2017-01-02 10:34:02 +03:00
|
|
|
// This could be needed for SSL client certificates
|
|
|
|
// We need to load them from keychain and try
|
|
|
|
reportResult( CredentialsMissingOrWrong );
|
2017-03-23 17:53:22 +03:00
|
|
|
} else if (! _account->credentials()->stillValid(reply)) {
|
2015-03-10 14:14:14 +03:00
|
|
|
_errors.append(tr("Authentication error: Either username or password are wrong."));
|
2017-03-23 17:53:22 +03:00
|
|
|
} else {
|
2015-09-13 03:57:49 +03:00
|
|
|
//_errors.append(tr("Unable to connect to %1").arg(_account->url().toString()));
|
2017-03-23 17:53:22 +03:00
|
|
|
_errors.append( job->errorString() );
|
2015-03-10 14:14:14 +03:00
|
|
|
}
|
2014-12-11 15:55:59 +03:00
|
|
|
reportResult( StatusNotFound );
|
2014-09-12 19:58:01 +04:00
|
|
|
}
|
|
|
|
|
2014-12-11 15:55:59 +03:00
|
|
|
void ConnectionValidator::slotJobTimeout(const QUrl &url)
|
2014-09-12 19:58:01 +04:00
|
|
|
{
|
2015-09-16 04:08:27 +03:00
|
|
|
Q_UNUSED(url);
|
2015-09-13 03:57:49 +03:00
|
|
|
//_errors.append(tr("Unable to connect to %1").arg(url.toString()));
|
2014-09-12 19:58:01 +04:00
|
|
|
_errors.append(tr("timeout"));
|
2014-12-11 17:43:48 +03:00
|
|
|
reportResult( Timeout );
|
2013-05-04 18:01:45 +04:00
|
|
|
}
|
|
|
|
|
2014-09-12 19:58:01 +04:00
|
|
|
|
2014-12-17 16:09:57 +03:00
|
|
|
void ConnectionValidator::checkAuthentication()
|
2013-05-04 18:01:45 +04:00
|
|
|
{
|
2014-03-03 20:55:15 +04:00
|
|
|
AbstractCredentials *creds = _account->credentials();
|
2014-12-03 15:10:49 +03:00
|
|
|
|
2015-01-21 17:30:25 +03:00
|
|
|
if (!creds->ready()) { // The user canceled
|
|
|
|
reportResult(UserCanceledCredentials);
|
|
|
|
}
|
|
|
|
|
2013-05-04 18:01:45 +04:00
|
|
|
// simply GET the webdav root, will fail if credentials are wrong.
|
|
|
|
// continue in slotAuthCheck here :-)
|
2014-12-03 15:10:49 +03:00
|
|
|
qDebug() << "# Check whether authenticated propfind works.";
|
2013-11-22 17:01:11 +04:00
|
|
|
PropfindJob *job = new PropfindJob(_account, "/", this);
|
2015-11-23 23:47:30 +03:00
|
|
|
job->setTimeout(timeoutToUseMsec);
|
2013-11-22 17:01:11 +04:00
|
|
|
job->setProperties(QList<QByteArray>() << "getlastmodified");
|
|
|
|
connect(job, SIGNAL(result(QVariantMap)), SLOT(slotAuthSuccess()));
|
2016-02-10 17:38:21 +03:00
|
|
|
connect(job, SIGNAL(finishedWithError(QNetworkReply*)), SLOT(slotAuthFailed(QNetworkReply*)));
|
2013-11-22 17:01:11 +04:00
|
|
|
job->start();
|
2013-05-04 18:01:45 +04:00
|
|
|
}
|
|
|
|
|
2013-10-28 23:01:59 +04:00
|
|
|
void ConnectionValidator::slotAuthFailed(QNetworkReply *reply)
|
2013-05-04 18:01:45 +04:00
|
|
|
{
|
2017-03-23 17:53:22 +03:00
|
|
|
auto job = qobject_cast<PropfindJob *>(sender());
|
2014-12-11 17:43:48 +03:00
|
|
|
Status stat = Timeout;
|
2013-05-04 18:01:45 +04:00
|
|
|
|
2013-10-28 23:01:59 +04:00
|
|
|
if( reply->error() == QNetworkReply::AuthenticationRequiredError ||
|
2015-03-03 10:33:59 +03:00
|
|
|
!_account->credentials()->stillValid(reply)) {
|
2017-03-23 17:53:22 +03:00
|
|
|
qDebug() << reply->error() << job->errorString();
|
2013-05-04 18:01:45 +04:00
|
|
|
qDebug() << "******** Password is wrong!";
|
2013-09-11 12:24:31 +04:00
|
|
|
_errors << tr("The provided credentials are not correct");
|
2015-09-05 16:37:20 +03:00
|
|
|
stat = CredentialsMissingOrWrong;
|
2013-11-25 18:33:35 +04:00
|
|
|
|
2013-10-28 23:01:59 +04:00
|
|
|
} else if( reply->error() != QNetworkReply::NoError ) {
|
2017-03-23 17:53:22 +03:00
|
|
|
_errors << job->errorStringParsingBody();
|
2015-02-25 11:49:39 +03:00
|
|
|
|
|
|
|
const int httpStatus =
|
|
|
|
reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
|
|
|
if ( httpStatus == 503 ) {
|
2015-04-24 12:32:47 +03:00
|
|
|
_errors.clear();
|
|
|
|
stat = ServiceUnavailable;
|
2015-02-25 11:49:39 +03:00
|
|
|
}
|
2013-05-04 18:01:45 +04:00
|
|
|
}
|
|
|
|
|
2014-12-11 15:55:59 +03:00
|
|
|
reportResult( stat );
|
2013-05-04 18:01:45 +04:00
|
|
|
}
|
|
|
|
|
2013-10-23 16:48:44 +04:00
|
|
|
void ConnectionValidator::slotAuthSuccess()
|
|
|
|
{
|
2014-12-11 15:55:59 +03:00
|
|
|
_errors.clear();
|
2015-02-05 17:18:38 +03:00
|
|
|
if (!_isCheckingServerAndAuth) {
|
|
|
|
reportResult(Connected);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
checkServerCapabilities();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ConnectionValidator::checkServerCapabilities()
|
|
|
|
{
|
|
|
|
JsonApiJob *job = new JsonApiJob(_account, QLatin1String("ocs/v1.php/cloud/capabilities"), this);
|
2016-04-27 13:19:49 +03:00
|
|
|
job->setTimeout(timeoutToUseMsec);
|
2017-04-26 13:15:33 +03:00
|
|
|
QObject::connect(job, SIGNAL(jsonReceived(QJsonDocument, int)), this, SLOT(slotCapabilitiesRecieved(QJsonDocument)));
|
2015-02-05 17:18:38 +03:00
|
|
|
job->start();
|
|
|
|
}
|
|
|
|
|
2017-04-26 13:15:33 +03:00
|
|
|
void ConnectionValidator::slotCapabilitiesRecieved(const QJsonDocument &json)
|
2015-02-05 17:18:38 +03:00
|
|
|
{
|
2017-04-26 13:15:33 +03:00
|
|
|
auto caps = json.object().value("ocs").toObject().value("data").toObject().value("capabilities").toObject();
|
2015-02-05 17:18:38 +03:00
|
|
|
qDebug() << "Server capabilities" << caps;
|
2017-04-26 13:15:33 +03:00
|
|
|
_account->setCapabilities(caps.toVariantMap());
|
2017-04-19 12:02:03 +03:00
|
|
|
|
|
|
|
// New servers also report the version in the capabilities
|
2017-04-26 13:15:33 +03:00
|
|
|
QString serverVersion = caps["core"].toObject()["status"].toObject()["version"].toString();
|
2017-04-19 12:02:03 +03:00
|
|
|
if (!serverVersion.isEmpty() && !setAndCheckServerVersion(serverVersion)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-09-16 16:49:43 +03:00
|
|
|
fetchUser();
|
2014-12-11 15:55:59 +03:00
|
|
|
}
|
|
|
|
|
2016-09-16 16:49:43 +03:00
|
|
|
void ConnectionValidator::fetchUser()
|
|
|
|
{
|
|
|
|
|
|
|
|
JsonApiJob *job = new JsonApiJob(_account, QLatin1String("ocs/v1.php/cloud/user"), this);
|
|
|
|
job->setTimeout(timeoutToUseMsec);
|
2017-04-26 13:15:33 +03:00
|
|
|
QObject::connect(job, SIGNAL(jsonReceived(QJsonDocument, int)), this, SLOT(slotUserFetched(QJsonDocument)));
|
2016-09-16 16:49:43 +03:00
|
|
|
job->start();
|
|
|
|
}
|
|
|
|
|
2017-04-19 12:02:03 +03:00
|
|
|
bool ConnectionValidator::setAndCheckServerVersion(const QString& version)
|
|
|
|
{
|
|
|
|
qDebug() << _account->url() << "has server version" << version;
|
|
|
|
_account->setServerVersion(version);
|
|
|
|
|
|
|
|
// We cannot deal with servers < 5.0.0
|
|
|
|
if (_account->serverVersionInt()
|
|
|
|
&& _account->serverVersionInt() < Account::makeServerVersion(5, 0, 0)) {
|
|
|
|
_errors.append( tr("The configured server for this client is too old") );
|
|
|
|
_errors.append( tr("Please update to the latest server and restart the client.") );
|
|
|
|
reportResult( ServerVersionMismatch );
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We attempt to work with servers >= 5.0.0 but warn users.
|
|
|
|
// Check usages of Account::serverVersionUnsupported() for details.
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-04-26 13:15:33 +03:00
|
|
|
void ConnectionValidator::slotUserFetched(const QJsonDocument &json)
|
2016-09-16 16:49:43 +03:00
|
|
|
{
|
2017-04-26 13:15:33 +03:00
|
|
|
QString user = json.object().value("ocs").toObject().value("data").toObject().value("id").toString();
|
2016-09-16 16:49:43 +03:00
|
|
|
if (!user.isEmpty()) {
|
2016-11-23 19:08:17 +03:00
|
|
|
_account->setDavUser(user);
|
2017-01-22 15:55:08 +03:00
|
|
|
|
|
|
|
AvatarJob *job = new AvatarJob(_account, this);
|
2017-01-23 23:35:12 +03:00
|
|
|
job->setTimeout(20*1000);
|
2017-03-10 00:34:36 +03:00
|
|
|
QObject::connect(job, SIGNAL(avatarPixmap(QImage)), this, SLOT(slotAvatarImage(QImage)));
|
2017-01-22 15:55:08 +03:00
|
|
|
|
|
|
|
job->start();
|
2016-09-16 16:49:43 +03:00
|
|
|
}
|
2017-01-22 15:55:08 +03:00
|
|
|
}
|
|
|
|
|
2017-03-10 00:34:36 +03:00
|
|
|
void ConnectionValidator::slotAvatarImage(const QImage& img)
|
2017-01-22 15:55:08 +03:00
|
|
|
{
|
2017-03-10 00:34:36 +03:00
|
|
|
_account->setAvatar(img);
|
2016-09-16 16:49:43 +03:00
|
|
|
reportResult(Connected);
|
|
|
|
}
|
2015-02-05 17:18:38 +03:00
|
|
|
|
2014-12-11 15:55:59 +03:00
|
|
|
void ConnectionValidator::reportResult(Status status)
|
|
|
|
{
|
|
|
|
emit connectionResult(status, _errors);
|
|
|
|
deleteLater();
|
2013-05-04 18:01:45 +04:00
|
|
|
}
|
2013-10-23 16:48:44 +04:00
|
|
|
|
2014-11-10 00:34:07 +03:00
|
|
|
} // namespace OCC
|