Comparar commits

...

42 Commits

Autor SHA1 Mensagem Data
Markus Goetz 5cabac73ad WiP: Download debug info about mtimes 2017-01-05 12:46:32 +01:00
Gerhard Wiesinger 4900db0099 Hopefully fixed issue #5375: [NTFS on a VeraCrypt Volume] Windows clients play ping-pong forever 2017-01-03 17:28:35 +01:00
Christian Kamm 084146756b Account: Fix displayName() #5413
This displayName() seemed to be based on Account::user() which used
to call _credentials->user(). But then we repurposed user() to be
davUser() and this usage wasn't updated to point back to the username
used for the credentials.
2017-01-03 13:54:59 +01:00
ckamm e1f5a49c21 Don't blacklist 507 Insufficent Storage #5346 (#5424) 2017-01-03 13:48:32 +01:00
ckamm 143320341e Build: Enable Q_ASSERT in release mode (#5425) 2017-01-03 13:42:25 +01:00
Christian Kamm e286bb1b64 Wizard: Don't accidentally pre-fill url field #5412
slotUrlEditFinished() is called when the wizard is triggered in
some situations.
2017-01-03 11:53:40 +01:00
Olivier Goffart d433f0e08e HTTPCreds: remove all cookies when logging out (#5383)
Some custom server use persistent cookies with the auth token. So we should
clear all the cookies when disconnecting.
Account::clearCookieJar is only called from the HTTPCredentials. This funciton
is not used for shibboleth.
There is probably no reasons to keep the HTTP cookie anyway.

Issue #5370
2017-01-03 11:39:10 +01:00
Christian Kamm 107149d601 Doc: Improve example #5422 2017-01-03 11:31:51 +01:00
Christian Kamm fa9b36f829 Wizard: Let the user know if url is invalid #5398 2017-01-03 11:28:56 +01:00
Christian Kamm 6775292d63 Fix compile of tests 2017-01-03 10:52:39 +01:00
Christian Kamm 6835429a28 Sql: Allow prepare fail for PRAGMA quick_check #5357
This actually happens in low-disk situations.
2017-01-03 10:43:29 +01:00
Christian Kamm 22135f9f57 Fixup broken authType on load #5408 2017-01-03 10:38:20 +01:00
Jenkins for ownCloud 0fd06a225c [tx-robot] updated from transifex 2017-01-03 02:19:30 +01:00
Christian Kamm 473dcb0947 Only create a FolderWatcher if the path exists
Also retry creating it before each sync.

See #5317
2017-01-02 08:52:26 +01:00
Christian Kamm e306f4611c Reschedule a folder regularly with some delay for some errors
Like "folder doesn't exist" - such that we will detect when the folder
becomes available and start syncing.

See #5317
2017-01-02 08:52:26 +01:00
Markus Goetz c6f4f44619 Fix up SSL client certificates #5213 #69 (#5289)
The re-enables the UI, uses Qt API for importing and
stores the certificate/key in the system keychain.
People who had set up client certs need to re-setup the account. This is ok
since it was an undocumented feature anyway.
2017-01-02 08:34:02 +01:00
Jenkins for ownCloud 0865c63745 [tx-robot] updated from transifex 2017-01-02 02:19:26 +01:00
Jenkins for ownCloud b81c3a6a67 [tx-robot] updated from transifex 2017-01-01 02:19:32 +01:00
Jenkins for ownCloud cc56e5639d [tx-robot] updated from transifex 2016-12-30 02:18:34 +01:00
Jenkins for ownCloud 3ce5b358ae [tx-robot] updated from transifex 2016-12-25 02:18:27 +01:00
Jenkins for ownCloud e968284618 [tx-robot] updated from transifex 2016-12-24 02:18:26 +01:00
Jenkins for ownCloud c7723179d8 [tx-robot] updated from transifex 2016-12-23 02:18:34 +01:00
Jenkins for ownCloud 1872f3f94a [tx-robot] updated from transifex 2016-12-22 02:18:30 +01:00
Christian Kamm 3b7887ca35 Wizard: Detach saved account from wizard
Fixes #5408 #5407.

The problem was that cleanup of the credentials page set the
credentials of the account back to dummy, thereby overriding
things like shib usernames.

This should be broken since a932eac832.
2016-12-21 15:31:12 +01:00
Piotr Mrówczyński d781e63fab Add capability to disable parallel chunked upload #5364 - technical review (#5403) 2016-12-21 15:08:45 +01:00
Kyle Fazzari d1237cdda3 Correctly handle possible missing GIT_SHA1. (#5401)
Currently, if get_git_head_revision() doesn't define GIT_SHA1 (which it
doesn't in some cases) it's possible to end up with the following error:

    CMake Error at CMakeLists.txt:69 (if):
      if given arguments:

        "STREQUAL" "GITDIR-NOTFOUND"

      Unknown arguments specified

Fix this by making sure both left and right hand arguments to STREQUAL
are always strings, even if GIT_SHA1 is undefined.

Signed-off-by: Kyle Fazzari <kyle@canonical.com>
2016-12-21 14:14:26 +01:00
Christian Kamm 030e3a5d4a Increase initial bandwidth estimates #4428 #5390
To 2 MB/s and 10 files/s.
2016-12-21 08:53:47 +01:00
Jenkins for ownCloud 4fa4a6a5ed [tx-robot] updated from transifex 2016-12-21 02:18:28 +01:00
Phil Davis 23fb07240b Fix Mac PATH command
Reported in the doc repo owncloud/documentation#1618
This version as suggested by @jturcotte
2016-12-20 20:01:38 +01:00
Christian Kamm 3912dba33a Move qDeclareMetatype from Folder to SyncEngine 2016-12-20 11:43:39 +01:00
Christian Kamm d8c479ab1e Don't wipe db if check fails while disk space is low #5357
An experimental fix for the issue, merged because it's low risk and
makes testing easier.
2016-12-20 09:33:59 +01:00
Jenkins for ownCloud bec67455c1 [tx-robot] updated from transifex 2016-12-20 02:18:27 +01:00
Jenkins for ownCloud ba6a37a601 [tx-robot] updated from transifex 2016-12-19 02:18:28 +01:00
Jenkins for ownCloud 03f5091e73 [tx-robot] updated from transifex 2016-12-18 02:18:28 +01:00
Jenkins for ownCloud 6b6ff08821 [tx-robot] updated from transifex 2016-12-17 02:18:27 +01:00
Jenkins for ownCloud 35a0ee4893 [tx-robot] updated from transifex 2016-12-16 02:18:29 +01:00
Jenkins for ownCloud 3519391119 [tx-robot] updated from transifex 2016-12-15 02:18:37 +01:00
Olivier Goffart 775a1c9ad8 FolderStatusModel: Fix insert/remove items when there are labels
Otherwise it might happen that the model is inconsistant and this can
lead to crash in the worst case.

(For example, if there was a "fetching" label, and we hide it because it
was a 404. In this case, we would not call begin/endRemoveRows, so the
view could still call the model with an index of row 0, that used to be
for the label, but now correspond to the first element of _subs. And
because _subs is empty, this could lead to crashes)
2016-12-14 14:13:47 +01:00
Olivier Goffart ac95844ebd Propagator: make sure every network job has a parent
This could make sure that the network job gets deleted if the parent job gets
deleted, and would avoid crashes like:

Crash: EXCEPTION_ACCESS_VIOLATION_READ at 0xffffffff8b008a04
  File "qiodevice.cpp", line 1617, in QIODevice::errorString
  File "propagatedownload.cpp", line 264, in OCC::GETFileJob::slotReadyRead
  File "moc_propagatedownload.cpp", line 85, in OCC::GETFileJob::qt_static_metacall
  File "qobject.cpp", line 3716, in QMetaObject::activate
  File "moc_qiodevice.cpp", line 154, in QIODevice::readyRead
  File "qnetworkreplyhttpimpl.cpp", line 1045, in QNetworkReplyHttpImplPrivate::replyDownloadData

(#5329)
2016-12-14 14:13:47 +01:00
Olivier Goffart c5b90d9507 Account::slotHandleSslErrors: add guards in case the reply gets deleted in the dialog event loop
Since slotHandleSslErrors will show a dialog with an eventloop, it could be
That the reply gets deleted. Guard against that.

(#5329)
2016-12-14 14:13:47 +01:00
Christian Kamm d631f2e070 Sync now: Disable on disconnect, rename while running #2158 2016-12-13 15:28:52 +01:00
Jonathan Kawohl 5bae2ed5ef fixed merge conflicts 2016-12-13 09:12:50 +01:00
74 arquivos alterados com 5914 adições e 5751 exclusões
+4 -1
Ver Arquivo
@@ -58,6 +58,9 @@ if( UNIX AND NOT APPLE )
endif()
####
# Enable Q_ASSERT etc. in all builds
add_definitions( -DQT_FORCE_ASSERTS )
include(GNUInstallDirs)
include(DefineInstallationPaths)
include(GenerateExportHeader)
@@ -69,7 +72,7 @@ get_git_head_revision(GIT_REFSPEC GIT_SHA1)
# if we cannot get it from git, directly try .tag (packages)
# this will work if the tar balls have been properly created
# via git-archive.
if (${GIT_SHA1} STREQUAL "GITDIR-NOTFOUND")
if ("${GIT_SHA1}" STREQUAL "GITDIR-NOTFOUND")
file(READ ${CMAKE_SOURCE_DIR}/.tag sha1_candidate)
string(REPLACE "\n" "" sha1_candidate ${sha1_candidate})
if (NOT ${sha1_candidate} STREQUAL "$Format:%H$")
-5
Ver Arquivo
@@ -44,11 +44,6 @@
extern "C" {
#endif
struct csync_client_certs_s {
char *certificatePath;
char *certificatePasswd;
};
enum csync_status_codes_e {
CSYNC_STATUS_OK = 0,
-3
Ver Arquivo
@@ -103,9 +103,6 @@ struct csync_s {
} callbacks;
c_strlist_t *excludes;
// needed for SSL client certificate support
struct csync_client_certs_s *clientCerts;
struct {
char *file;
+1 -9
Ver Arquivo
@@ -68,17 +68,9 @@ To set up your build environment for development using HomeBrew_:
1. Install Xcode
2. Install Xcode command line tools::
<<<<<<< HEAD
xcode-select --install
3. Install homebrew::
=======
xcode-select --install
3. Install homebrew::
>>>>>>> ca9ec4625391ae23940b3a62aaa0afe89f3d98e8
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
4. Add the ownCloud repository using the following command::
@@ -91,7 +83,7 @@ To set up your build environment for development using HomeBrew_:
3. Add Qt from brew to the path::
export PATH=/usr/local/Cellar/qt5/5.x.y/bin/qmake
export PATH=/usr/local/Cellar/qt5/5.x.y/bin:$PATH
Where ``x.z`` is the current version of Qt 5 that brew has installed
on your machine.
+1 -1
Ver Arquivo
@@ -65,7 +65,7 @@ If no client is configured, or if you choose to use a different user to synchron
you can specify the user
password setting with the usual URL pattern. For example::
$ owncloudcmd / https://carla:secret@server/owncloud/remote.php/webdav/
$ owncloudcmd /home/user/my_sync_folder https://carla:secret@server/owncloud/remote.php/webdav/
To synchronize the ownCloud directory ``Music`` to the local directory
``media/music``, through a proxy listening on port ``8080``, and on a gateway
+45
Ver Arquivo
@@ -571,6 +571,51 @@ X-GNOME-Autostart-Delay=3
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
Comment[oc]=@APPLICATION_NAME@ sincronizacion del client
GenericName[oc]=Dorsièr de Sincronizacion
-110
Ver Arquivo
@@ -1,110 +0,0 @@
/*
* Copyright (C) by Pierre MOREAU <p.moreau@agim.idshost.fr>
*
* 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
* the Free Software Foundation; version 2 of the License.
*
* 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.
*/
/**
* \file p12topem.cpp
* \brief Static library to convert p12 to pem
* \author Pierre MOREAU <p.moreau@agim.idshost.fr>
* \version 1.0.0
* \date 09 January 2014
*/
#include "p12topem.h"
/**
* \fn string x509ToString (BIO)
* \brief Return string from BIO SSL
* \param BIO o PEM_write_BIO_...
* \return string PEM
*/
string x509ToString(BIO *o) {
BUF_MEM *bptr;
BIO_get_mem_ptr(o, &bptr);
int len = bptr->length;
void* data = calloc(len+10, sizeof(char));
BIO_read(o, data, len);
string ret = std::string(static_cast<char*>(data));
free(data);
return ret;
}
/**
* \fn resultP12ToPem p12ToPem (string, string)
* \brief Convert P12 to PEM
* \param string p12File Path to P12 file
* \param string p12Passwd Password to open P12 file
* \return result (bool ReturnCode, Int ErrorCode, String Comment, String PrivateKey, String Certificate)
*/
resultP12ToPem p12ToPem(string p12File, string p12Passwd) {
FILE *fp;
PKCS12 *p12 = NULL;
EVP_PKEY *pkey = NULL;
X509 *cert = NULL;
STACK_OF(X509) *ca = NULL;
BIO *o = BIO_new(BIO_s_mem());
string privateKey = "";
string certificate = "";
resultP12ToPem ret;
ret.ReturnCode = false;
ret.ErrorCode = 0;
ret.Comment = "";
ret.PrivateKey = "";
ret.Certificate = "";
SSLeay_add_all_algorithms();
ERR_load_crypto_strings();
if(!(fp = fopen(p12File.c_str(), "rb"))) {
ret.ErrorCode = 1;
ret.Comment = strerror(errno);
return ret;
}
p12 = d2i_PKCS12_fp(fp, &p12);
fclose (fp);
if (!p12) {
ret.ErrorCode = 2;
ret.Comment = "Unable to open PKCS#12 file";
return ret;
}
if (!PKCS12_parse(p12, p12Passwd.c_str(), &pkey, &cert, &ca)) {
ret.ErrorCode = 3;
ret.Comment = "Unable to parse PKCS#12 file (wrong password ?)";
return ret;
}
PKCS12_free(p12);
if (!(pkey && cert)) {
ret.ErrorCode = 4;
ret.Comment = "Certificate and/or key file doesn't exists";
} else {
PEM_write_bio_PrivateKey(o, pkey, 0, 0, 0, NULL, 0);
privateKey = x509ToString(o);
PEM_write_bio_X509(o, cert);
certificate = x509ToString(o);
BIO_free(o);
ret.ReturnCode = true;
ret.ErrorCode = 0;
ret.Comment = "All is fine";
ret.PrivateKey = privateKey;
ret.Certificate = certificate;
}
return ret;
}
-62
Ver Arquivo
@@ -1,62 +0,0 @@
/*
* Copyright (C) by Pierre MOREAU <p.moreau@agim.idshost.fr>
*
* 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
* the Free Software Foundation; version 2 of the License.
*
* 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.
*/
#ifndef P12TOPEM_H
#define P12TOPEM_H
/**
* \file p12topem.h
* \brief Static library to convert p12 to pem
* \author Pierre MOREAU <p.moreau@agim.idshost.fr>
* \version 1.0.0
* \date 09 January 2014
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <openssl/pkcs12.h>
using namespace std;
/**
* \struct resultP12ToPem p12topem.h
*/
struct resultP12ToPem {
bool ReturnCode;
int ErrorCode;
string Comment;
string PrivateKey;
string Certificate;
};
/**
* \brief Return string from BIO SSL
* \param BIO o PEM_write_BIO_...
* \return string PEM
*/
string x509ToString(BIO *o);
/**
* \brief Convert P12 to PEM
* \param string p12File Path to P12 file
* \param string p12Passwd Password to open P12 file
* \return result (bool ReturnCode, Int ErrorCode, String Comment, String PrivateKey, String Certificate)
*/
resultP12ToPem p12ToPem(string p12File, string p12Passwd);
#endif /* P12TOPEM_H */
+2 -2
Ver Arquivo
@@ -121,7 +121,7 @@ QString queryPassword(const QString &user)
class HttpCredentialsText : public HttpCredentials {
public:
HttpCredentialsText(const QString& user, const QString& password)
: HttpCredentials(user, password, "", ""), // FIXME: not working with client certs yet (qknight)
: HttpCredentials(user, password), // FIXME: not working with client certs yet (qknight)
_sslTrusted(false)
{}
@@ -507,7 +507,7 @@ restart_sync:
app.exec();
if (engine.isAnotherSyncNeeded()) {
if (engine.isAnotherSyncNeeded() != NoFollowUpSync) {
if (restartCount < options.restartTimes) {
restartCount++;
qDebug() << "Restarting Sync, because another sync is needed" << restartCount;
-1
Ver Arquivo
@@ -151,7 +151,6 @@ set(3rdparty_SRC
../3rdparty/qtsingleapplication/qtlocalpeer.cpp
../3rdparty/qtsingleapplication/qtsingleapplication.cpp
../3rdparty/qtsingleapplication/qtsinglecoreapplication.cpp
../3rdparty/certificates/p12topem.cpp
)
if (APPLE)
+12 -1
Ver Arquivo
@@ -214,6 +214,17 @@ AccountPtr AccountManager::loadAccountHelper(QSettings& settings)
auto acc = createAccount();
QString authType = settings.value(QLatin1String(authTypeC)).toString();
// There was an account-type saving bug when 'skip folder config' was used
// See #5408. This attempts to fix up the "dummy" authType
if (authType == QLatin1String("dummy")) {
if (settings.contains(QLatin1String("http_user"))) {
authType = "http";
} else if (settings.contains(QLatin1String("shibboleth_shib_user"))) {
authType = "shibboleth";
}
}
QString overrideUrl = Theme::instance()->overrideServerUrl();
QString forceAuth = Theme::instance()->forceConfigAuthType();
if(!forceAuth.isEmpty() && !overrideUrl.isEmpty() ) {
@@ -237,7 +248,7 @@ AccountPtr AccountManager::loadAccountHelper(QSettings& settings)
acc->setCredentials(CredentialsFactory::create(authType));
// now the cert, it is in the general group
// now the server cert, it is in the general group
settings.beginGroup(QLatin1String("General"));
acc->setApprovedCerts(QSslCertificate::fromData(settings.value(caCertsKeyC).toByteArray()));
settings.endGroup();
+6
Ver Arquivo
@@ -214,8 +214,10 @@ void AccountSettings::slotCustomContextMenuRequested(const QPoint &pos)
}
tv->setCurrentIndex(index);
QString alias = _model->data( index, FolderStatusDelegate::FolderAliasRole ).toString();
bool folderPaused = _model->data( index, FolderStatusDelegate::FolderSyncPaused).toBool();
bool folderConnected = _model->data( index, FolderStatusDelegate::FolderAccountConnected ).toBool();
auto folderMan = FolderMan::instance();
QMenu *menu = new QMenu(tv);
menu->setAttribute(Qt::WA_DeleteOnClose);
@@ -231,6 +233,10 @@ void AccountSettings::slotCustomContextMenuRequested(const QPoint &pos)
if (!folderPaused) {
ac = menu->addAction(tr("Force sync now"));
if (folderMan->currentSyncFolder() == folderMan->folder(alias)) {
ac->setText(tr("Restart sync"));
}
ac->setEnabled(folderConnected);
connect(ac, SIGNAL(triggered(bool)), this, SLOT(slotForceSyncCurrentFolder()));
}
+2 -2
Ver Arquivo
@@ -10,7 +10,7 @@
<x>0</x>
<y>0</y>
<width>462</width>
<height>186</height>
<height>188</height>
</rect>
</property>
<property name="windowTitle">
@@ -32,7 +32,7 @@
<item row="0" column="0">
<widget class="QLabel" name="labelCertificateFile">
<property name="text">
<string>Certificate :</string>
<string>Certificate &amp; Key (pkcs12) :</string>
</property>
</widget>
</item>
+1 -1
Ver Arquivo
@@ -27,7 +27,7 @@ class HttpCredentialsGui : public HttpCredentials {
Q_OBJECT
public:
explicit HttpCredentialsGui() : HttpCredentials() {}
HttpCredentialsGui(const QString& user, const QString& password, const QString& certificatePath, const QString& certificatePasswd) : HttpCredentials(user, password, certificatePath, certificatePasswd) {}
HttpCredentialsGui(const QString& user, const QString& password, const QSslCertificate& certificate, const QSslKey& key) : HttpCredentials(user, password, certificate, key) {}
void askFromUser() Q_DECL_OVERRIDE;
Q_INVOKABLE void askFromUserAsync();
+3 -6
Ver Arquivo
@@ -65,9 +65,6 @@ Folder::Folder(const FolderDefinition& definition,
, _fileLog(new SyncRunFileLog)
, _saveBackwardsCompatible(false)
{
qRegisterMetaType<SyncFileItemVector>("SyncFileItemVector");
qRegisterMetaType<SyncFileItem::Direction>("SyncFileItem::Direction");
qsrand(QTime::currentTime().msec());
_timeSinceLastSyncStart.start();
_timeSinceLastSyncDone.start();
@@ -826,7 +823,7 @@ void Folder::slotSyncFinished(bool success)
_fileLog->finish();
bubbleUpSyncResult();
bool anotherSyncNeeded = _engine->isAnotherSyncNeeded();
auto anotherSyncNeeded = _engine->isAnotherSyncNeeded();
if (_csyncError) {
_syncResult.setStatus(SyncResult::Error);
@@ -877,7 +874,7 @@ void Folder::slotSyncFinished(bool success)
_timeSinceLastSyncDone.restart();
// Increment the follow-up sync counter if necessary.
if (anotherSyncNeeded) {
if (anotherSyncNeeded == ImmediateFollowUp) {
_consecutiveFollowUpSyncs++;
qDebug() << "another sync was requested by the finished sync, this has"
<< "happened" << _consecutiveFollowUpSyncs << "times";
@@ -886,7 +883,7 @@ void Folder::slotSyncFinished(bool success)
}
// Maybe force a follow-up sync to take place, but only a couple of times.
if (anotherSyncNeeded && _consecutiveFollowUpSyncs <= 3)
if (anotherSyncNeeded == ImmediateFollowUp && _consecutiveFollowUpSyncs <= 3)
{
// Sometimes another sync is requested because a local file is still
// changing, so wait at least a small amount of time before syncing
+17 -10
Ver Arquivo
@@ -148,6 +148,7 @@ int FolderMan::unloadAndDeleteAllFolders()
void FolderMan::registerFolderMonitor( Folder *folder )
{
if( !folder ) return;
if( !QDir(folder->path()).exists() ) return;
if( !_folderWatchers.contains(folder->alias() ) ) {
FolderWatcher *fw = new FolderWatcher(folder->path(), folder);
@@ -730,6 +731,10 @@ void FolderMan::slotStartScheduledFolderSync()
// Start syncing this folder!
if( folder ) {
// Safe to call several times, and necessary to try again if
// the folder path didn't exist previously.
registerFolderMonitor(folder);
_currentSyncFolder = folder;
folder->startSync( QStringList() );
}
@@ -833,18 +838,20 @@ void FolderMan::slotScheduleFolderByTime()
continue;
}
// Retry a couple of times after failure
bool syncAgainAfterFail = f->consecutiveFailingSyncs() > 0 && f->consecutiveFailingSyncs() < 3;
qint64 syncAgainAfterFailDelay = 10 * 1000; // 10s for the first retry-after-fail
// Retry a couple of times after failure; or regularly if requested
bool syncAgain =
(f->consecutiveFailingSyncs() > 0 && f->consecutiveFailingSyncs() < 3)
|| f->syncEngine().isAnotherSyncNeeded() == DelayedFollowUp;
qint64 syncAgainDelay = 10 * 1000; // 10s for the first retry-after-fail
if (f->consecutiveFailingSyncs() > 1)
syncAgainAfterFailDelay = 60 * 1000; // 60s for each further attempt
if (syncAgainAfterFail
&& msecsSinceSync > syncAgainAfterFailDelay) {
syncAgainDelay = 60 * 1000; // 60s for each further attempt
if (syncAgain
&& msecsSinceSync > syncAgainDelay) {
qDebug() << "** scheduling folder" << f->alias()
<< "because the last"
<< f->consecutiveFailingSyncs() << "syncs failed, last status:"
<< f->syncResult().statusString()
<< "time since last sync:" << msecsSinceSync;
<< ", the last" << f->consecutiveFailingSyncs() << "syncs failed"
<< ", anotherSyncNeeded" << f->syncEngine().isAnotherSyncNeeded()
<< ", last status:" << f->syncResult().statusString()
<< ", time since last sync:" << msecsSinceSync;
scheduleFolder(f);
continue;
+6 -9
Ver Arquivo
@@ -527,10 +527,8 @@ void FolderStatusModel::fetchMore(const QModelIndex& parent)
if (!info || info->_fetched || info->_fetching)
return;
info->_hasError = false;
info->resetSubs(this, parent);
info->_fetching = true;
info->_fetchingLabel = false;
QString path = info->_folder->remotePath();
if (info->_path != QLatin1String("/")) {
if (!path.endsWith(QLatin1Char('/'))) {
@@ -698,17 +696,16 @@ void FolderStatusModel::slotLscolFinishedWithError(QNetworkReply* r)
qDebug() << r->errorString();
parentInfo->_lastErrorString = r->errorString();
parentInfo->resetSubs(this, idx);
if (r->error() == QNetworkReply::ContentNotFoundError) {
parentInfo->_fetched = true;
} else {
if (!parentInfo->hasLabel()) {
beginInsertRows(idx, 0, 0);
endInsertRows();
}
Q_ASSERT(!parentInfo->hasLabel());
beginInsertRows(idx, 0, 0);
parentInfo->_hasError = true;
endInsertRows();
}
parentInfo->_fetching = false;
parentInfo->_fetchingLabel = false;
}
}
+13 -1
Ver Arquivo
@@ -207,10 +207,15 @@ void OwncloudSetupWizard::slotNoOwnCloudFoundAuth(QNetworkReply *reply)
QString contentType = reply->header(QNetworkRequest::ContentTypeHeader).toString();
// Do this early because reply might be deleted in message box event loop
QString msg = tr("Failed to connect to %1 at %2:<br/>%3")
QString msg;
if (!_ocWizard->account()->url().isValid()) {
msg = tr("Invalid URL");
} else {
msg = tr("Failed to connect to %1 at %2:<br/>%3")
.arg(Theme::instance()->appNameGUI(),
reply->url().toString(),
reply->errorString());
}
bool isDowngradeAdvised = checkDowngradeAdvised(reply);
// If a client cert is needed, nginx sends:
@@ -553,6 +558,13 @@ void OwncloudSetupWizard::slotSkipFolderConfiguration()
AccountState *OwncloudSetupWizard::applyAccountChanges()
{
AccountPtr newAccount = _ocWizard->account();
// Detach the account that is going to be saved from the
// wizard to ensure it doesn't accidentally get modified
// later (such as from running cleanup such as
// AbstractCredentialsWizardPage::cleanupPage())
_ocWizard->setAccount(AccountManager::createAccount());
auto manager = AccountManager::instance();
auto newState = manager->addAccount(newAccount);
@@ -29,8 +29,11 @@ OwncloudConnectionMethodDialog::OwncloudConnectionMethodDialog(QWidget *parent)
connect(ui->btnClientSideTLS, SIGNAL(clicked(bool)), this, SLOT(returnClientSideTLS()));
connect(ui->btnBack, SIGNAL(clicked(bool)), this, SLOT(returnBack()));
// DM: TLS Client Cert GUI support disabled for now
#if QT_VERSION < QT_VERSION_CHECK(5, 4, 0)
// We support only from Qt 5.4.x because of https://doc.qt.io/qt-5/qsslcertificate.html#importPkcs12
ui->btnClientSideTLS->hide();
#endif
}
void OwncloudConnectionMethodDialog::setUrl(const QUrl &url)
+1 -1
Ver Arquivo
@@ -192,7 +192,7 @@ void OwncloudHttpCredsPage::setErrorString(const QString& err)
AbstractCredentials* OwncloudHttpCredsPage::getCredentials() const
{
return new HttpCredentialsGui(_ui.leUsername->text(), _ui.lePassword->text(), _ocWizard->ownCloudCertificatePath, _ocWizard->ownCloudCertificatePasswd);
return new HttpCredentialsGui(_ui.leUsername->text(), _ui.lePassword->text(), _ocWizard->_clientSslCertificate, _ocWizard->_clientSslKey);
}
+31 -31
Ver Arquivo
@@ -21,13 +21,13 @@
#include <QMessageBox>
#include <QSsl>
#include <QSslCertificate>
#include <QNetworkAccessManager>
#include "QProgressIndicator.h"
#include "wizard/owncloudwizardcommon.h"
#include "wizard/owncloudsetuppage.h"
#include "wizard/owncloudconnectionmethoddialog.h"
#include "../3rdparty/certificates/p12topem.h"
#include "theme.h"
#include "account.h"
@@ -71,7 +71,6 @@ OwncloudSetupPage::OwncloudSetupPage(QWidget *parent)
connect(_ui.leUrl, SIGNAL(editingFinished()), SLOT(slotUrlEditFinished()));
addCertDial = new AddCertificateDialog(this);
connect(_ocWizard,SIGNAL(needCertificate()),this,SLOT(slotAskSSLClientCertificate()));
}
void OwncloudSetupPage::setServerUrl( const QString& newUrl )
@@ -139,7 +138,7 @@ void OwncloudSetupPage::slotUrlChanged(const QString& url)
void OwncloudSetupPage::slotUrlEditFinished()
{
QString url = _ui.leUrl->fullText();
if (QUrl(url).isRelative()) {
if (QUrl(url).isRelative() && !url.isEmpty()) {
// no scheme defined, set one
url.prepend("https://");
}
@@ -269,7 +268,10 @@ void OwncloudSetupPage::setErrorString( const QString& err, bool retryHTTPonly )
}
break;
case OwncloudConnectionMethodDialog::Client_Side_TLS:
slotAskSSLClientCertificate();
#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)
addCertDial->show();
connect(addCertDial, SIGNAL(accepted()),this,SLOT(slotCertificateAccepted()));
#endif
break;
case OwncloudConnectionMethodDialog::Closed:
case OwncloudConnectionMethodDialog::Back:
@@ -302,12 +304,6 @@ void OwncloudSetupPage::stopSpinner()
_progressIndi->stopAnimation();
}
void OwncloudSetupPage::slotAskSSLClientCertificate()
{
addCertDial->show();
connect(addCertDial, SIGNAL(accepted()),this,SLOT(slotCertificateAccepted()));
}
QString subjectInfoHelper(const QSslCertificate& cert, const QByteArray &qa)
{
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
@@ -320,36 +316,40 @@ QString subjectInfoHelper(const QSslCertificate& cert, const QByteArray &qa)
//called during the validation of the client certificate.
void OwncloudSetupPage::slotCertificateAccepted()
{
QSslCertificate sslCertificate;
resultP12ToPem certif = p12ToPem(addCertDial->getCertificatePath().toStdString() , addCertDial->getCertificatePasswd().toStdString());
if(certif.ReturnCode){
QString s = QString::fromStdString(certif.Certificate);
QByteArray ba = s.toLocal8Bit();
QList<QSslCertificate> sslCertificateList = QSslCertificate::fromData(ba, QSsl::Pem);
sslCertificate = sslCertificateList.takeAt(0);
_ocWizard->ownCloudCertificate = ba;
_ocWizard->ownCloudPrivateKey = certif.PrivateKey.c_str();
_ocWizard->ownCloudCertificatePath = addCertDial->getCertificatePath();
_ocWizard->ownCloudCertificatePasswd = addCertDial->getCertificatePasswd();
#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)
QList<QSslCertificate> clientCaCertificates;
QFile certFile(addCertDial->getCertificatePath());
certFile.open(QFile::ReadOnly);
if(QSslCertificate::importPkcs12(&certFile,
&_ocWizard->_clientSslKey, &_ocWizard->_clientSslCertificate,
&clientCaCertificates,
addCertDial->getCertificatePasswd().toLocal8Bit())){
AccountPtr acc = _ocWizard->account();
acc->setCertificate(_ocWizard->ownCloudCertificate, _ocWizard->ownCloudPrivateKey);
addCertDial->reinit();
// to re-create the session ticket because we added a key/cert
acc->setSslConfiguration(QSslConfiguration());
QSslConfiguration sslConfiguration = acc->getOrCreateSslConfig();
// We're stuffing the certificate into the configuration form here. Later the
// cert will come via the HttpCredentials
sslConfiguration.setLocalCertificate(_ocWizard->_clientSslCertificate);
sslConfiguration.setPrivateKey(_ocWizard->_clientSslKey);
acc->setSslConfiguration(sslConfiguration);
// Make sure TCP connections get re-established
acc->networkAccessManager()->clearAccessCache();
addCertDial->reinit(); // FIXME: Why not just have this only created on use?
validatePage();
} else {
QString message;
message = certif.Comment.c_str();
addCertDial->showErrorMessage(message);
addCertDial->showErrorMessage("Could not load certificate");
addCertDial->show();
}
#endif
}
OwncloudSetupPage::~OwncloudSetupPage()
{
delete addCertDial;
}
} // namespace OCC
-1
Ver Arquivo
@@ -59,7 +59,6 @@ public slots:
void setErrorString( const QString&, bool retryHTTPonly );
void startSpinner();
void stopSpinner();
void slotAskSSLClientCertificate();
void slotCertificateAccepted();
protected slots:
-7
Ver Arquivo
@@ -224,11 +224,4 @@ AbstractCredentials* OwncloudWizard::getCredentials() const
return 0;
}
// outputs the signal needed to authenticate a certificate
void OwncloudWizard::raiseCertificatePopup()
{
emit needCertificate();
}
} // end namespace
+6 -5
Ver Arquivo
@@ -17,6 +17,8 @@
#define MIRALL_OWNCLOUD_WIZARD_H
#include <QWizard>
#include <QSslKey>
#include <QSslCertificate>
#include "wizard/owncloudwizardcommon.h"
#include "accountfwd.h"
@@ -63,11 +65,10 @@ public:
void displayError( const QString&, bool retryHTTPonly);
AbstractCredentials* getCredentials() const;
void raiseCertificatePopup();
QByteArray ownCloudCertificate;
QString ownCloudPrivateKey;
QString ownCloudCertificatePath;
QString ownCloudCertificatePasswd;
// FIXME: Can those be local variables?
// Set from the OwncloudSetupPage, later used from OwncloudHttpCredsPage
QSslKey _clientSslKey;
QSslCertificate _clientSslCertificate;
public slots:
void setAuthType(WizardCommon::AuthType type);
-1
Ver Arquivo
@@ -70,7 +70,6 @@ set(libsync_SRCS
creds/abstractcredentials.cpp
creds/credentialscommon.cpp
../3rdparty/qjson/json.cpp
../3rdparty/certificates/p12topem.cpp
)
if(TOKEN_AUTH_ONLY)
+11 -33
Ver Arquivo
@@ -18,7 +18,6 @@
#include "configfile.h"
#include "accessmanager.h"
#include "creds/abstractcredentials.h"
#include "../3rdparty/certificates/p12topem.h"
#include "capabilities.h"
#include "theme.h"
@@ -93,7 +92,7 @@ void Account::setDavUser(const QString &newDavUser)
QString Account::displayName() const
{
QString dn = QString("%1@%2").arg(davUser(), _url.host());
QString dn = QString("%1@%2").arg(_credentials->user(), _url.host());
int port = url().port();
if (port > 0 && port != 80 && port != 443) {
dn.append(QLatin1Char(':'));
@@ -149,10 +148,14 @@ QUrl Account::davUrl() const
return Utility::concatUrlPath(url(), davPath());
}
/**
* clear all cookies. (Session cookies or not)
*/
void Account::clearCookieJar()
{
Q_ASSERT(qobject_cast<CookieJar*>(_am->cookieJar()));
static_cast<CookieJar*>(_am->cookieJar())->clearSessionCookies();
static_cast<CookieJar*>(_am->cookieJar())->setAllCookies(QList<QNetworkCookie>());
emit wantsAccountSaved(this);
}
/*! This shares our official cookie jar (containing all the tasty
@@ -242,12 +245,6 @@ QNetworkReply *Account::davRequest(const QByteArray &verb, const QUrl &url, QNet
return _am->sendCustomRequest(req, verb, data);
}
void Account::setCertificate(const QByteArray certficate, const QString privateKey)
{
_pemCertificate=certficate;
_pemPrivateKey=privateKey;
}
void Account::setSslConfiguration(const QSslConfiguration &config)
{
_sslConfiguration = config;
@@ -264,31 +261,7 @@ QSslConfiguration Account::getOrCreateSslConfig()
// if setting the client certificate fails, you will probably get an error similar to this:
// "An internal error number 1060 happened. SSL handshake failed, client certificate was requested: SSL error: sslv3 alert handshake failure"
QSslConfiguration sslConfig = QSslConfiguration::defaultConfiguration();
QSslCertificate sslClientCertificate;
ConfigFile cfgFile;
if(!cfgFile.certificatePath().isEmpty() && !cfgFile.certificatePasswd().isEmpty()) {
resultP12ToPem certif = p12ToPem(cfgFile.certificatePath().toStdString(), cfgFile.certificatePasswd().toStdString());
QString s = QString::fromStdString(certif.Certificate);
QByteArray ba = s.toLocal8Bit();
this->setCertificate(ba, QString::fromStdString(certif.PrivateKey));
}
if((!_pemCertificate.isEmpty())&&(!_pemPrivateKey.isEmpty())) {
// Read certificates
QList<QSslCertificate> sslCertificateList = QSslCertificate::fromData(_pemCertificate, QSsl::Pem);
if(sslCertificateList.length() != 0) {
sslClientCertificate = sslCertificateList.takeAt(0);
}
// Read key from file
QSslKey privateKey(_pemPrivateKey.toLocal8Bit(), QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey , "");
// SSL configuration
sslConfig.setCaCertificates(QSslSocket::systemCaCertificates());
sslConfig.setLocalCertificate(sslClientCertificate);
sslConfig.setPrivateKey(privateKey);
qDebug() << "Added SSL client certificate to the query";
}
#if QT_VERSION > QT_VERSION_CHECK(5, 2, 0)
// Try hard to re-use session for different requests
sslConfig.setSslOption(QSsl::SslOptionDisableSessionTickets, false);
@@ -379,8 +352,11 @@ void Account::slotHandleSslErrors(QNetworkReply *reply , QList<QSslError> errors
// Keep a ref here on our stackframe to make sure that it doesn't get deleted before
// handleErrors returns.
QSharedPointer<QNetworkAccessManager> qnamLock = _am;
QPointer<QObject> guard = reply;
if (_sslErrorHandler->handleErrors(errors, reply->sslConfiguration(), &approvedCerts, sharedFromThis())) {
if (!guard) return;
QSslSocket::addDefaultCaCertificates(approvedCerts);
addApprovedCerts(approvedCerts);
emit wantsAccountSaved(this);
@@ -392,6 +368,8 @@ void Account::slotHandleSslErrors(QNetworkReply *reply , QList<QSslError> errors
// certificate changes.
reply->ignoreSslErrors(errors);
} else {
if (!guard) return;
// Mark all involved certificates as rejected, so we don't ask the user again.
foreach (const QSslError &error, errors) {
if (!_rejectedCertificates.contains(error.certificate())) {
+1 -2
Ver Arquivo
@@ -224,8 +224,7 @@ private:
QList<QSslCertificate> _rejectedCertificates;
static QString _configFileName;
QByteArray _pemCertificate;
QString _pemPrivateKey;
QString _davPath; // defaults to value from theme, might be overwritten in brandings
friend class AccountManager;
};
+4
Ver Arquivo
@@ -116,5 +116,9 @@ bool Capabilities::chunkingNg() const
return _capabilities["dav"].toMap()["chunking"].toByteArray() >= "1.0";
}
bool Capabilities::chunkingParallelUploadDisabled() const
{
return _capabilities["dav"].toMap()["chunkingParallelUploadDisabled"].toBool();
}
}
+3
Ver Arquivo
@@ -42,6 +42,9 @@ public:
bool shareResharing() const;
bool chunkingNg() const;
/// disable parallel upload in chunking
bool chunkingParallelUploadDisabled() const;
/// returns true if the capabilities report notifications
bool notificationsAvailable() const;
+6 -1
Ver Arquivo
@@ -144,7 +144,12 @@ void ConnectionValidator::slotStatusFound(const QUrl&url, const QVariantMap &inf
// status.php could not be loaded (network or server issue!).
void ConnectionValidator::slotNoStatusFound(QNetworkReply *reply)
{
qDebug() << Q_FUNC_INFO << reply->error() << reply->errorString();
qDebug() << Q_FUNC_INFO << reply->error() << reply->errorString() << reply->peek(1024);
if (reply && !_account->credentials()->ready()) {
// This could be needed for SSL client certificates
// We need to load them from keychain and try
reportResult( CredentialsMissingOrWrong );
} else
if( reply && ! _account->credentials()->stillValid(reply)) {
_errors.append(tr("Authentication error: Either username or password are wrong."));
} else {
+129 -47
Ver Arquivo
@@ -17,6 +17,7 @@
#include <QDebug>
#include <QNetworkReply>
#include <QSettings>
#include <QSslKey>
#include <keychain.h>
@@ -36,8 +37,8 @@ namespace OCC
namespace
{
const char userC[] = "user";
const char certifPathC[] = "certificatePath";
const char certifPasswdC[] = "certificatePasswd";
const char clientCertificatePEMC[] = "_clientCertificatePEM";
const char clientKeyPEMC[] = "_clientKeyPEM";
const char authenticationFailedC[] = "owncloud-authentication-failed";
} // ns
@@ -50,24 +51,47 @@ protected:
QByteArray credHash = QByteArray(_cred->user().toUtf8()+":"+_cred->password().toUtf8()).toBase64();
QNetworkRequest req(request);
req.setRawHeader(QByteArray("Authorization"), QByteArray("Basic ") + credHash);
//qDebug() << "Request for " << req.url() << "with authorization" << QByteArray::fromBase64(credHash);
//qDebug() << "Request for " << req.url() << "with authorization"
// << QByteArray::fromBase64(credHash)
// << _cred->_clientSslKey << _cred->_clientSslCertificate
// << _cred->_clientSslKey.isNull() << _cred->_clientSslCertificate.isNull();
if (!_cred->_clientSslKey.isNull() && !_cred->_clientSslCertificate.isNull()) {
// SSL configuration
QSslConfiguration sslConfiguration = req.sslConfiguration();
sslConfiguration.setLocalCertificate(_cred->_clientSslCertificate);
sslConfiguration.setPrivateKey(_cred->_clientSslKey);
req.setSslConfiguration(sslConfiguration);
}
return AccessManager::createRequest(op, req, outgoingData);
}
private:
const HttpCredentials *_cred;
};
static void addSettingsToJob(Account *account, QKeychain::Job *job)
{
Q_UNUSED(account);
auto settings = Utility::settingsWithGroup(Theme::instance()->appName());
settings->setParent(job); // make the job parent to make setting deleted properly
job->setSettings(settings.release());
}
HttpCredentials::HttpCredentials()
: _ready(false)
{
}
HttpCredentials::HttpCredentials(const QString& user, const QString& password, const QString& certificatePath, const QString& certificatePasswd)
// From wizard
HttpCredentials::HttpCredentials(const QString& user, const QString& password, const QSslCertificate& certificate, const QSslKey& key)
: _user(user),
_password(password),
_ready(true),
_certificatePath(certificatePath),
_certificatePasswd(certificatePasswd)
_clientSslKey(key),
_clientSslCertificate(certificate)
{
}
@@ -86,16 +110,6 @@ QString HttpCredentials::password() const
return _password;
}
QString HttpCredentials::certificatePath() const
{
return _certificatePath;
}
QString HttpCredentials::certificatePasswd() const
{
return _certificatePasswd;
}
void HttpCredentials::setAccount(Account* account)
{
AbstractCredentials::setAccount(account);
@@ -129,35 +143,83 @@ void HttpCredentials::fetchFromKeychain()
{
// User must be fetched from config file
fetchUser();
_certificatePath = _account->credentialSetting(QLatin1String(certifPathC)).toString();
_certificatePasswd = _account->credentialSetting(QLatin1String(certifPasswdC)).toString();
auto settings = Utility::settingsWithGroup(Theme::instance()->appName());
const QString kck = keychainKey(_account->url().toString(), _user );
QString key = QString::fromLatin1( "%1/data" ).arg( kck );
if( settings && settings->contains(key) ) {
// Clean the password from the config file if it is in there.
// we do not want a security problem.
settings->remove(key);
key = QString::fromLatin1( "%1/type" ).arg( kck );
settings->remove(key);
settings->sync();
}
if (_ready) {
Q_EMIT fetched();
} else {
// Read client cert from keychain
const QString kck = keychainKey(_account->url().toString(), _user + clientCertificatePEMC);
ReadPasswordJob *job = new ReadPasswordJob(Theme::instance()->appName());
settings->setParent(job); // make the job parent to make setting deleted properly
job->setSettings(settings.release());
addSettingsToJob(_account, job);
job->setInsecureFallback(false);
job->setKey(kck);
connect(job, SIGNAL(finished(QKeychain::Job*)), SLOT(slotReadJobDone(QKeychain::Job*)));
qDebug() << "-------- ----->" << _clientSslCertificate << _clientSslKey;
connect(job, SIGNAL(finished(QKeychain::Job*)), SLOT(slotReadClientCertPEMJobDone(QKeychain::Job*)));
job->start();
}
}
void HttpCredentials::slotReadClientCertPEMJobDone(QKeychain::Job* incoming)
{
// Store PEM in memory
ReadPasswordJob *readJob = static_cast<ReadPasswordJob*>(incoming);
if (readJob->error() == NoError && readJob->binaryData().length() > 0) {
QList<QSslCertificate> sslCertificateList = QSslCertificate::fromData(readJob->binaryData(), QSsl::Pem);
if(sslCertificateList.length() >= 1) {
_clientSslCertificate = sslCertificateList.at(0);
}
}
// Load key too
const QString kck = keychainKey(_account->url().toString(), _user + clientKeyPEMC);
ReadPasswordJob *job = new ReadPasswordJob(Theme::instance()->appName());
addSettingsToJob(_account, job);
job->setInsecureFallback(false);
job->setKey(kck);
connect(job, SIGNAL(finished(QKeychain::Job*)), SLOT(slotReadClientKeyPEMJobDone(QKeychain::Job*)));
job->start();
}
void HttpCredentials::slotReadClientKeyPEMJobDone(QKeychain::Job* incoming)
{
// Store key in memory
ReadPasswordJob *readJob = static_cast<ReadPasswordJob*>(incoming);
if (readJob->error() == NoError && readJob->binaryData().length() > 0) {
QByteArray clientKeyPEM = readJob->binaryData();
// FIXME Unfortunately Qt has a bug and we can't just use QSsl::Opaque to let it
// load whatever we have. So we try until it works.
_clientSslKey = QSslKey(clientKeyPEM, QSsl::Rsa);
if (_clientSslKey.isNull()) {
_clientSslKey = QSslKey(clientKeyPEM, QSsl::Dsa);
}
#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)
// ec keys are Qt 5.5
if (_clientSslKey.isNull()) {
_clientSslKey = QSslKey(clientKeyPEM, QSsl::Ec);
}
#endif
if (_clientSslKey.isNull()) {
qDebug() << "Warning: Could not load SSL key into Qt!";
}
}
// Now fetch the actual server password
const QString kck = keychainKey(_account->url().toString(), _user );
ReadPasswordJob *job = new ReadPasswordJob(Theme::instance()->appName());
addSettingsToJob(_account, job);
job->setInsecureFallback(false);
job->setKey(kck);
connect(job, SIGNAL(finished(QKeychain::Job*)), SLOT(slotReadJobDone(QKeychain::Job*)));
job->start();
}
bool HttpCredentials::stillValid(QNetworkReply *reply)
{
return ((reply->error() != QNetworkReply::AuthenticationRequiredError)
@@ -166,10 +228,10 @@ bool HttpCredentials::stillValid(QNetworkReply *reply)
|| !reply->property(authenticationFailedC).toBool()));
}
void HttpCredentials::slotReadJobDone(QKeychain::Job *job)
void HttpCredentials::slotReadJobDone(QKeychain::Job *incomingJob)
{
ReadPasswordJob *readJob = static_cast<ReadPasswordJob*>(job);
_password = readJob->textData();
QKeychain::ReadPasswordJob *job = static_cast<ReadPasswordJob*>(incomingJob);
_password = job->textData();
if( _user.isEmpty()) {
qDebug() << "Strange: User is empty!";
@@ -178,7 +240,6 @@ void HttpCredentials::slotReadJobDone(QKeychain::Job *job)
QKeychain::Error error = job->error();
if( !_password.isEmpty() && error == NoError ) {
// All cool, the keychain did not come back with error.
// Still, the password can be empty which indicates a problem and
// the password dialog has to be opened.
@@ -214,9 +275,7 @@ void HttpCredentials::invalidateToken()
}
DeletePasswordJob *job = new DeletePasswordJob(Theme::instance()->appName());
auto settings = Utility::settingsWithGroup(Theme::instance()->appName());
settings->setParent(job); // make the job parent to make setting deleted properly
job->setSettings(settings.release());
addSettingsToJob(_account, job);
job->setInsecureFallback(true);
job->setKey(kck);
job->start();
@@ -261,14 +320,37 @@ void HttpCredentials::persist()
// We never connected or fetched the user, there is nothing to save.
return;
}
_account->setCredentialSetting(QLatin1String(userC), _user);
_account->setCredentialSetting(QLatin1String(certifPathC), _certificatePath);
_account->setCredentialSetting(QLatin1String(certifPasswdC), _certificatePasswd);
WritePasswordJob *job = new WritePasswordJob(Theme::instance()->appName());
auto settings = Utility::settingsWithGroup(Theme::instance()->appName());
settings->setParent(job); // make the job parent to make setting deleted properly
job->setSettings(settings.release());
_account->setCredentialSetting(QLatin1String(userC), _user);
// write cert
WritePasswordJob *job = new WritePasswordJob(Theme::instance()->appName());
addSettingsToJob(_account, job);
job->setInsecureFallback(false);
connect(job, SIGNAL(finished(QKeychain::Job*)), SLOT(slotWriteClientCertPEMJobDone(QKeychain::Job*)));
job->setKey(keychainKey(_account->url().toString(), _user + clientCertificatePEMC));
job->setBinaryData(_clientSslCertificate.toPem());
job->start();
}
void HttpCredentials::slotWriteClientCertPEMJobDone(Job *incomingJob)
{
Q_UNUSED(incomingJob);
// write ssl key
WritePasswordJob* job = new WritePasswordJob(Theme::instance()->appName());
addSettingsToJob(_account, job);
job->setInsecureFallback(false);
connect(job, SIGNAL(finished(QKeychain::Job*)), SLOT(slotWriteClientKeyPEMJobDone(QKeychain::Job*)));
job->setKey(keychainKey(_account->url().toString(), _user + clientKeyPEMC));
job->setBinaryData(_clientSslKey.toPem());
job->start();
}
void HttpCredentials::slotWriteClientKeyPEMJobDone(Job *incomingJob)
{
Q_UNUSED(incomingJob);
WritePasswordJob* job = new WritePasswordJob(Theme::instance()->appName());
addSettingsToJob(_account, job);
job->setInsecureFallback(false);
connect(job, SIGNAL(finished(QKeychain::Job*)), SLOT(slotWriteJobDone(QKeychain::Job*)));
job->setKey(keychainKey(_account->url().toString(), _user));
+15 -9
Ver Arquivo
@@ -17,7 +17,8 @@
#define MIRALL_CREDS_HTTP_CREDENTIALS_H
#include <QMap>
#include <QSslCertificate>
#include <QSslKey>
#include "creds/abstractcredentials.h"
class QNetworkReply;
@@ -25,6 +26,8 @@ class QAuthenticator;
namespace QKeychain {
class Job;
class WritePasswordJob;
class ReadPasswordJob;
}
namespace OCC
@@ -33,10 +36,10 @@ namespace OCC
class OWNCLOUDSYNC_EXPORT HttpCredentials : public AbstractCredentials
{
Q_OBJECT
friend class HttpCredentialsAccessManager;
public:
explicit HttpCredentials();
HttpCredentials(const QString& user, const QString& password, const QString& certificatePath, const QString& certificatePasswd);
HttpCredentials(const QString& user, const QString& password, const QSslCertificate& certificate = QSslCertificate(), const QSslKey& key = QSslKey());
QString authType() const Q_DECL_OVERRIDE;
QNetworkAccessManager* getQNAM() const Q_DECL_OVERRIDE;
@@ -50,15 +53,19 @@ public:
void forgetSensitiveData() Q_DECL_OVERRIDE;
QString fetchUser();
virtual bool sslIsTrusted() { return false; }
QString certificatePath() const;
QString certificatePasswd() const;
// To fetch the user name as early as possible
void setAccount(Account* account) Q_DECL_OVERRIDE;
private Q_SLOTS:
void slotAuthentication(QNetworkReply*, QAuthenticator*);
void slotReadClientCertPEMJobDone(QKeychain::Job*);
void slotReadClientKeyPEMJobDone(QKeychain::Job*);
void slotReadJobDone(QKeychain::Job*);
void slotWriteClientCertPEMJobDone(QKeychain::Job*);
void slotWriteClientKeyPEMJobDone(QKeychain::Job*);
void slotWriteJobDone(QKeychain::Job*);
void clearQNAMCache();
@@ -66,12 +73,11 @@ protected:
QString _user;
QString _password;
QString _previousPassword;
QString _fetchErrorString;
bool _ready;
private:
QString _certificatePath;
QString _certificatePasswd;
QSslKey _clientSslKey;
QSslCertificate _clientSslCertificate;
};
} // namespace OCC
+1 -1
Ver Arquivo
@@ -472,7 +472,7 @@ bool CheckServerJob::finished()
QVariantMap status = QtJson::parse(QString::fromUtf8(body), success).toMap();
// empty or invalid response
if (!success || status.isEmpty()) {
qDebug() << "status.php from server is not valid JSON!";
qDebug() << "status.php from server is not valid JSON!" << body << reply()->request().url();
}
qDebug() << "status.php returns: " << status << " " << reply()->error() << " Reply: " << reply();
+13 -3
Ver Arquivo
@@ -70,7 +70,9 @@ bool SqlDatabase::openHelper( const QString& filename, int sqliteFlags )
bool SqlDatabase::checkDb()
{
SqlQuery quick_check("PRAGMA quick_check;", *this);
// quick_check can fail with a disk IO error when diskspace is low
SqlQuery quick_check(*this);
quick_check.prepare("PRAGMA quick_check;", /*allow_failure=*/true);
if( !quick_check.exec() ) {
qDebug() << "Error running quick_check on database";
return false;
@@ -97,6 +99,14 @@ bool SqlDatabase::openOrCreateReadWrite( const QString& filename )
}
if( !checkDb() ) {
// When disk space is low, checking the db may fail even though it's fine.
qint64 freeSpace = Utility::freeDiskSpace(filename);
if (freeSpace < 1000000) {
qDebug() << "Consistency check failed, disk space is low, aborting" << freeSpace;
close();
return false;
}
qDebug() << "Consistency check failed, removing broken db" << filename;
close();
QFile::remove(filename);
@@ -191,7 +201,7 @@ SqlQuery::SqlQuery(const QString& sql, SqlDatabase& db)
prepare(sql);
}
int SqlQuery::prepare( const QString& sql)
int SqlQuery::prepare( const QString& sql, bool allow_failure )
{
QString s(sql);
_sql = s.trimmed();
@@ -213,7 +223,7 @@ int SqlQuery::prepare( const QString& sql)
if( _errId != SQLITE_OK ) {
_error = QString::fromUtf8(sqlite3_errmsg(_db));
qWarning() << "Sqlite prepare statement error:" << _error << "in" <<_sql;
Q_ASSERT(!"SQLITE Prepare error");
Q_ASSERT(allow_failure || !"SQLITE Prepare error");
}
}
return _errId;
+1 -1
Ver Arquivo
@@ -80,7 +80,7 @@ public:
bool isSelect();
bool isPragma();
bool exec();
int prepare( const QString& sql );
int prepare( const QString& sql, bool allow_failure = false );
bool next();
void bindValue(int pos, const QVariant& value);
QString lastQuery() const;
+6 -2
Ver Arquivo
@@ -145,8 +145,12 @@ void ProgressInfo::reset()
_sizeProgress = Progress();
_fileProgress = Progress();
_totalSizeOfCompletedJobs = 0;
_maxBytesPerSecond = 100000.0;
_maxFilesPerSecond = 2.0;
// Historically, these starting estimates were way lower, but that lead
// to gross overestimation of ETA when a good estimate wasn't available.
_maxBytesPerSecond = 2000000.0; // 2 MB/s
_maxFilesPerSecond = 10.0;
_updateEstimatesTimer.stop();
_lastCompletedItem = SyncFileItem();
}
+12 -2
Ver Arquivo
@@ -401,7 +401,7 @@ void PropagateDownloadFile::start()
// Normal job, download from oC instance
_job = new GETFileJob(_propagator->account(),
_propagator->_remoteFolder + _item->_file,
&_tmpFile, headers, expectedEtagForResume, _resumeStart);
&_tmpFile, headers, expectedEtagForResume, _resumeStart, this);
} else {
// We were provided a direct URL, use that one
qDebug() << Q_FUNC_INFO << "directDownloadUrl given for " << _item->_file << _item->_directDownloadUrl;
@@ -413,7 +413,7 @@ void PropagateDownloadFile::start()
QUrl url = QUrl::fromUserInput(_item->_directDownloadUrl);
_job = new GETFileJob(_propagator->account(),
url,
&_tmpFile, headers, expectedEtagForResume, _resumeStart);
&_tmpFile, headers, expectedEtagForResume, _resumeStart, this);
}
_job->setBandwidthManager(&_propagator->_bandwidthManager);
connect(_job, SIGNAL(finishedSignal()), this, SLOT(slotGetFinished()));
@@ -739,10 +739,12 @@ void PropagateDownloadFile::downloadFinished()
qDebug() << "Created conflict file" << fn << "->" << conflictFileName;
}
qDebug() << "1 We need to fetch the time again" << _item->_modtime;
FileSystem::setModTime(_tmpFile.fileName(), _item->_modtime);
// We need to fetch the time again because some file systems such as FAT have worse than a second
// Accuracy, and we really need the time from the file system. (#3103)
_item->_modtime = FileSystem::getModTime(_tmpFile.fileName());
qDebug() << "2 and we really need the time from the file system" << _item->_modtime;
if (FileSystem::fileExists(fn)) {
// Preserve the existing file permissions.
@@ -805,6 +807,14 @@ void PropagateDownloadFile::downloadFinished()
}
FileSystem::setFileHidden(fn, false);
qDebug() << "1 Set modification time of moved file again" << _item->_modtime;
// Set modification time of moved file again (because we modified permissions above and that changes modification time, depending on filesystem)
FileSystem::setModTime(fn, _item->_modtime);
// We need to fetch the time again because some file systems such as FAT have worse than a second
// Accuracy, and we really need the time from the file system. (#3103)
_item->_modtime = FileSystem::getModTime(fn);
qDebug() << "2 and we really need the time from the file system" << _item->_modtime;
// Maybe we downloaded a newer version of the file than we thought we would...
// Get up to date information for the journal.
_item->_size = FileSystem::getSize(fn);
+1 -1
Ver Arquivo
@@ -315,7 +315,7 @@ void PropagateUploadFileNG::startNextChunk()
QUrl url = chunkUrl(_currentChunk);
// job takes ownership of device via a QScopedPointer. Job deletes itself when finishing
PUTFileJob* job = new PUTFileJob(_propagator->account(), url, device, headers, _currentChunk);
PUTFileJob* job = new PUTFileJob(_propagator->account(), url, device, headers, _currentChunk, this);
_jobs.append(job);
connect(job, SIGNAL(finishedSignal()), this, SLOT(slotPutFinished()));
connect(job, SIGNAL(uploadProgress(qint64,qint64)),
+16 -9
Ver Arquivo
@@ -123,7 +123,7 @@ void PropagateUploadFileV1::startNextChunk()
}
// job takes ownership of device via a QScopedPointer. Job deletes itself when finishing
PUTFileJob* job = new PUTFileJob(_propagator->account(), _propagator->_remoteFolder + path, device, headers, _currentChunk);
PUTFileJob* job = new PUTFileJob(_propagator->account(), _propagator->_remoteFolder + path, device, headers, _currentChunk, this);
_jobs.append(job);
connect(job, SIGNAL(finishedSignal()), this, SLOT(slotPutFinished()));
connect(job, SIGNAL(uploadProgress(qint64,qint64)), this, SLOT(slotUploadProgress(qint64,qint64)));
@@ -134,18 +134,25 @@ void PropagateUploadFileV1::startNextChunk()
_currentChunk++;
bool parallelChunkUpload = true;
QByteArray env = qgetenv("OWNCLOUD_PARALLEL_CHUNK");
if (!env.isEmpty()) {
parallelChunkUpload = env != "false" && env != "0";
if (_propagator->account()->capabilities().chunkingParallelUploadDisabled()) {
// Server may also disable parallel chunked upload for any higher version
parallelChunkUpload = false;
} else {
int versionNum = _propagator->account()->serverVersionInt();
if (versionNum < 0x080003) {
// Disable parallel chunk upload severs older than 8.0.3 to avoid too many
// internal sever errors (#2743, #2938)
parallelChunkUpload = false;
QByteArray env = qgetenv("OWNCLOUD_PARALLEL_CHUNK");
if (!env.isEmpty()) {
parallelChunkUpload = env != "false" && env != "0";
} else {
int versionNum = _propagator->account()->serverVersionInt();
if (versionNum < 0x080003) {
// Disable parallel chunk upload severs older than 8.0.3 to avoid too many
// internal sever errors (#2743, #2938)
parallelChunkUpload = false;
}
}
}
if (_currentChunk + _startChunk >= _chunkCount - 1) {
// Don't do parallel upload of chunk if this might be the last chunk because the server cannot handle that
// https://github.com/owncloud/core/issues/11106
+11 -5
Ver Arquivo
@@ -73,11 +73,13 @@ SyncEngine::SyncEngine(AccountPtr account, const QString& localPath,
, _downloadLimit(0)
, _newBigFolderSizeLimit(-1)
, _checksum_hook(journal)
, _anotherSyncNeeded(false)
, _anotherSyncNeeded(NoFollowUpSync)
{
qRegisterMetaType<SyncFileItem>("SyncFileItem");
qRegisterMetaType<SyncFileItem::Status>("SyncFileItem::Status");
qRegisterMetaType<SyncFileStatus>("SyncFileStatus");
qRegisterMetaType<SyncFileItemVector>("SyncFileItemVector");
qRegisterMetaType<SyncFileItem::Direction>("SyncFileItem::Direction");
// Everything in the SyncEngine expects a trailing slash for the localPath.
Q_ASSERT(localPath.endsWith(QLatin1Char('/')));
@@ -693,12 +695,13 @@ void SyncEngine::startSync()
Q_ASSERT(!_syncRunning);
s_anySyncRunning = true;
_syncRunning = true;
_anotherSyncNeeded = false;
_anotherSyncNeeded = NoFollowUpSync;
_clearTouchedFilesTimer.stop();
_progressInfo->reset();
if (!QDir(_localPath).exists()) {
_anotherSyncNeeded = DelayedFollowUp;
// No _tr, it should only occur in non-mirall
emit csyncError("Unable to find local sync folder.");
finalize(false);
@@ -712,6 +715,7 @@ void SyncEngine::startSync()
qDebug() << "There are" << freeBytes << "bytes available at" << _localPath
<< "and at least" << minFree << "are required";
if (freeBytes < minFree) {
_anotherSyncNeeded = DelayedFollowUp;
emit csyncError(tr("Only %1 are available, need at least %2 to start",
"Placeholders are postfixed with file sizes using Utility::octetsToString()").arg(
Utility::octetsToString(freeBytes),
@@ -1048,7 +1052,9 @@ void SyncEngine::slotItemCompleted(const SyncFileItem &item, const PropagatorJob
void SyncEngine::slotFinished(bool success)
{
_anotherSyncNeeded = _anotherSyncNeeded || _propagator->_anotherSyncNeeded;
if (_propagator->_anotherSyncNeeded && _anotherSyncNeeded == NoFollowUpSync) {
_anotherSyncNeeded = ImmediateFollowUp;
}
if (success) {
_journal->setDataFingerprint(_discoveryMainThread->_dataFingerprint);
@@ -1171,7 +1177,7 @@ void SyncEngine::checkForPermission()
// be restored. Do that in the next sync by not considering as a rename
// but delete and upload. It will then be restored if needed.
_journal->avoidRenamesOnNextSync((*it)->_file);
_anotherSyncNeeded = true;
_anotherSyncNeeded = ImmediateFollowUp;
qDebug() << "Moving of " << (*it)->_file << " canceled because no permission to add parent folder";
}
(*it)->_instruction = CSYNC_INSTRUCTION_ERROR;
@@ -1328,7 +1334,7 @@ void SyncEngine::checkForPermission()
// At this point we would need to go back to the propagate phase on both remote to take
// the decision.
_journal->avoidRenamesOnNextSync((*it)->_file);
_anotherSyncNeeded = true;
_anotherSyncNeeded = ImmediateFollowUp;
if ((*it)->_isDirectory) {
+10 -3
Ver Arquivo
@@ -49,6 +49,13 @@ class SyncJournalDb;
class OwncloudPropagator;
class PropagatorJob;
enum AnotherSyncNeeded
{
NoFollowUpSync,
ImmediateFollowUp, // schedule this again immediately (limited amount of times)
DelayedFollowUp // regularly schedule this folder again (around 1/minute, unlimited)
};
/**
* @brief The SyncEngine class
* @ingroup libsync
@@ -82,8 +89,8 @@ public:
Utility::StopWatch &stopWatch() { return _stopWatch; }
SyncFileStatusTracker &syncFileStatusTracker() { return *_syncFileStatusTracker; }
/* Return true if we detected that another sync is needed to complete the sync */
bool isAnotherSyncNeeded() { return _anotherSyncNeeded; }
/* Returns whether another sync is needed to complete the sync */
AnotherSyncNeeded isAnotherSyncNeeded() { return _anotherSyncNeeded; }
/** Get the ms since a file was touched, or -1 if it wasn't.
*
@@ -259,7 +266,7 @@ private:
/// Hook for computing checksums from csync_update
CSyncChecksumHook _checksum_hook;
bool _anotherSyncNeeded;
AnotherSyncNeeded _anotherSyncNeeded;
/** Stores the time since a job touched a file. */
QHash<QString, QElapsedTimer> _touchedFiles;
+1
Ver Arquivo
@@ -131,6 +131,7 @@ SyncJournalErrorBlacklistRecord SyncJournalErrorBlacklistRecord::update(
bool mayBlacklist =
item._errorMayBeBlacklisted // explicitly flagged for blacklisting
|| (item._httpErrorCode != 0 // or non-local error
&& item._httpErrorCode != 507 // Don't blacklist "Insufficient Storage"
#ifdef OWNCLOUD_5XX_NO_BLACKLIST
&& item._httpErrorCode / 100 != 5 // In this configuration, never blacklist error 5xx
#endif
+1 -1
Ver Arquivo
@@ -23,7 +23,7 @@ using namespace OCC;
class HttpCredentialsTest : public HttpCredentials {
public:
HttpCredentialsTest(const QString& user, const QString& password)
: HttpCredentials(user, password, "", "")
: HttpCredentials(user, password)
{}
void askFromUser() Q_DECL_OVERRIDE {
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff