From ea40e314d404c81878f902a60e1a0688ca82a15e Mon Sep 17 00:00:00 2001 From: Christian Kamm Date: Tue, 12 Apr 2016 10:12:35 +0200 Subject: [PATCH] Add server capabilities for checksums #4638 * Add checksums/supportedTypes and checksums/preferredUploadType capabilities. The default is that no checksum types are supported. * Remove the transmissionChecksum config option. Servers must now use the capabilities to indicate that they are fine with the client sending checksums. Note: This intentionally breaks brandings that overrode Theme::transmissionChecksum. The override must be removed and the server's capabilities must be adjusted to include the new values. --- src/libsync/capabilities.cpp | 20 +++++--------------- src/libsync/capabilities.h | 26 ++++++++++++++++++++------ src/libsync/checksums.cpp | 7 ++++--- src/libsync/checksums.h | 4 ++-- src/libsync/configfile.cpp | 15 ++++++--------- src/libsync/configfile.h | 12 +++++++----- src/libsync/owncloudpropagator.cpp | 15 --------------- src/libsync/propagatedownload.cpp | 2 +- src/libsync/propagateupload.cpp | 2 +- src/libsync/theme.cpp | 5 ----- src/libsync/theme.h | 8 -------- 11 files changed, 46 insertions(+), 70 deletions(-) diff --git a/src/libsync/capabilities.cpp b/src/libsync/capabilities.cpp index d6d2eafd58e..0dfff767efd 100644 --- a/src/libsync/capabilities.cpp +++ b/src/libsync/capabilities.cpp @@ -81,28 +81,18 @@ bool Capabilities::isValid() const return !_capabilities.isEmpty(); } -QList Capabilities::supportedChecksumTypesAdvertised() const -{ - return QList(); -} - QList Capabilities::supportedChecksumTypes() const { - auto list = supportedChecksumTypesAdvertised(); - QByteArray cfgType = ConfigFile().transmissionChecksum().toLatin1(); - if (!cfgType.isEmpty()) { - list.prepend(cfgType); + QList list; + foreach (const auto & t, _capabilities["checksums"].toMap()["supportedTypes"].toList()) { + list.push_back(t.toByteArray()); } return list; } -QByteArray Capabilities::preferredChecksumType() const +QByteArray Capabilities::preferredUploadChecksumType() const { - auto list = supportedChecksumTypes(); - if (list.isEmpty()) { - return QByteArray(); - } - return list.first(); + return _capabilities["checksums"].toMap()["preferredUploadType"].toByteArray(); } } diff --git a/src/libsync/capabilities.h b/src/libsync/capabilities.h index c3297f22438..70290bf976b 100644 --- a/src/libsync/capabilities.h +++ b/src/libsync/capabilities.h @@ -46,14 +46,28 @@ class OWNCLOUDSYNC_EXPORT Capabilities { /// returns true if the capabilities are loaded already. bool isValid() const; - /// Returns the checksum types the server explicitly advertises - QList supportedChecksumTypesAdvertised() const; - - /// Like supportedChecksumTypesRaw(), but includes the type from the config + /** + * Returns the checksum types the server understands. + * + * When the client uses one of these checksumming algorithms in + * the OC-Checksum header of a file upload, the server will use + * it to validate that data was transmitted correctly. + * + * Path: checksums/supportedTypes + * Default: [] + * Possible entries: "Adler32", "MD5", "SHA1" + */ QList supportedChecksumTypes() const; - /// Returns the checksum type that should be used for new uploads. - QByteArray preferredChecksumType() const; + /** + * The checksum algorithm that the server recommends for file uploads. + * This is just a preference, any algorithm listed in supportedTypes may be used. + * + * Path: checksums/preferredUploadType + * Default: empty, meaning "no preference" + * Possible values: empty or any of the supportedTypes + */ + QByteArray preferredUploadChecksumType() const; private: QVariantMap _capabilities; diff --git a/src/libsync/checksums.cpp b/src/libsync/checksums.cpp index 99101fd244b..3a17825ad8a 100644 --- a/src/libsync/checksums.cpp +++ b/src/libsync/checksums.cpp @@ -17,6 +17,7 @@ #include "syncfileitem.h" #include "propagatorjobs.h" #include "account.h" +#include "configfile.h" #include @@ -108,10 +109,10 @@ bool uploadChecksumEnabled() return enabled; } -bool downloadChecksumEnabled() +bool downloadChecksumValidationEnabled() { - static bool enabled = qgetenv("OWNCLOUD_DISABLE_CHECKSUM_DOWNLOAD").isEmpty(); - return enabled; + static bool disabledByConfig = ConfigFile().disableDownloadChecksumValidation(); + return !disabledByConfig; } QByteArray contentChecksumType() diff --git a/src/libsync/checksums.h b/src/libsync/checksums.h index 519c74b7170..670e3c0b418 100644 --- a/src/libsync/checksums.h +++ b/src/libsync/checksums.h @@ -34,8 +34,8 @@ bool parseChecksumHeader(const QByteArray& header, QByteArray* type, QByteArray* /// Checks OWNCLOUD_DISABLE_CHECKSUM_UPLOAD bool uploadChecksumEnabled(); -/// Checks OWNCLOUD_DISABLE_CHECKSUM_DOWNLOAD -bool downloadChecksumEnabled(); +/// Checks disableDownloadChecksumValidation from the config file +bool downloadChecksumValidationEnabled(); /// Checks OWNCLOUD_CONTENT_CHECKSUM_TYPE (default: SHA1) QByteArray contentChecksumType(); diff --git a/src/libsync/configfile.cpp b/src/libsync/configfile.cpp index a0c5b144282..931349a98c1 100644 --- a/src/libsync/configfile.cpp +++ b/src/libsync/configfile.cpp @@ -52,7 +52,7 @@ static const char updateCheckIntervalC[] = "updateCheckInterval"; static const char geometryC[] = "geometry"; static const char timeoutC[] = "timeout"; static const char chunkSizeC[] = "chunkSize"; -static const char transmissionChecksumC[] = "transmissionChecksum"; +static const char disableDownloadChecksumValidationC[] = "disableDownloadChecksumValidation"; static const char proxyHostC[] = "Proxy/host"; static const char proxyTypeC[] = "Proxy/type"; @@ -129,18 +129,15 @@ quint64 ConfigFile::chunkSize() const return settings.value(QLatin1String(chunkSizeC), 10*1000*1000).toLongLong(); // default to 10 MB } -QString ConfigFile::transmissionChecksum() const +bool ConfigFile::disableDownloadChecksumValidation() const { QSettings settings(configFile(), QSettings::IniFormat); - QString checksum = settings.value(QLatin1String(transmissionChecksumC), QString()).toString(); - - if( checksum.isEmpty() ) { - // if the config file setting is empty, maybe the Branding requires it. - checksum = Theme::instance()->transmissionChecksum(); + QVariant value = settings.value(QLatin1String(disableDownloadChecksumValidationC)); + if (!value.isValid()) { + return false; } - - return checksum; + return value.toBool(); } void ConfigFile::setOptionalDesktopNotifications(bool show) diff --git a/src/libsync/configfile.h b/src/libsync/configfile.h index d45a9693ff3..361a82b13c7 100644 --- a/src/libsync/configfile.h +++ b/src/libsync/configfile.h @@ -114,11 +114,13 @@ class OWNCLOUDSYNC_EXPORT ConfigFile int timeout() const; quint64 chunkSize() const; - // send a checksum as a header along with the transmission or not. - // possible values: - // empty: no checksum calculated or expected. - // or "Adler32", "MD5", "SHA1" - QString transmissionChecksum() const; + /** Whether to disable download checksum validation. + * + * By default (false) received checksums will be validated. This flag + * can disable checksum validation and is intended for debugging purposes + * only. + */ + bool disableDownloadChecksumValidation() const; void saveGeometry(QWidget *w); void restoreGeometry(QWidget *w); diff --git a/src/libsync/owncloudpropagator.cpp b/src/libsync/owncloudpropagator.cpp index 04e592f9d50..dce440391f3 100644 --- a/src/libsync/owncloudpropagator.cpp +++ b/src/libsync/owncloudpropagator.cpp @@ -299,21 +299,6 @@ void OwncloudPropagator::start(const SyncFileItemVector& items) { Q_ASSERT(std::is_sorted(items.begin(), items.end())); - /* Check and log the transmission checksum type */ - ConfigFile cfg; - const QString checksumType = cfg.transmissionChecksum(); - - /* if the checksum type is empty, it is not sent. No error */ - if( !checksumType.isEmpty() ) { - if( checksumType == checkSumAdlerC || - checksumType == checkSumMD5C || - checksumType == checkSumSHA1C ) { - qDebug() << "Client sends transmission checksum type" << checksumType; - } else { - qWarning() << "Unknown transmission checksum type from config" << checksumType; - } - } - /* This builds all the jobs needed for the propagation. * Each directory is a PropagateDirectory job, which contains the files in it. * In order to do that we loop over the items. (which are sorted by destination) diff --git a/src/libsync/propagatedownload.cpp b/src/libsync/propagatedownload.cpp index eb804203bb8..41170b6afcb 100644 --- a/src/libsync/propagatedownload.cpp +++ b/src/libsync/propagatedownload.cpp @@ -555,7 +555,7 @@ void PropagateDownloadFileQNAM::slotGetFinished() connect(validator, SIGNAL(validationFailed(QString)), SLOT(slotChecksumFail(QString))); auto checksumHeader = job->reply()->rawHeader(checkSumHeaderC); - if (!downloadChecksumEnabled()) { + if (!downloadChecksumValidationEnabled()) { checksumHeader.clear(); } validator->start(_tmpFile.fileName(), checksumHeader); diff --git a/src/libsync/propagateupload.cpp b/src/libsync/propagateupload.cpp index b11c47707ad..f46bf28b3b2 100644 --- a/src/libsync/propagateupload.cpp +++ b/src/libsync/propagateupload.cpp @@ -261,7 +261,7 @@ void PropagateUploadFileQNAM::slotComputeTransmissionChecksum(const QByteArray& // Compute the transmission checksum. auto computeChecksum = new ComputeChecksum(this); if (uploadChecksumEnabled()) { - computeChecksum->setChecksumType(_propagator->account()->capabilities().preferredChecksumType()); + computeChecksum->setChecksumType(_propagator->account()->capabilities().preferredUploadChecksumType()); } else { computeChecksum->setChecksumType(QByteArray()); } diff --git a/src/libsync/theme.cpp b/src/libsync/theme.cpp index e2f673b6269..3b6eea9effd 100644 --- a/src/libsync/theme.cpp +++ b/src/libsync/theme.cpp @@ -248,11 +248,6 @@ QString Theme::updateCheckUrl() const return QLatin1String("https://updates.owncloud.com/client/"); } -QString Theme::transmissionChecksum() const -{ - return QString::null; // No transmission by default. -} - qint64 Theme::newBigFolderSizeLimit() const { // Default to 500MB diff --git a/src/libsync/theme.h b/src/libsync/theme.h index c9df0145304..b57afb62ea4 100644 --- a/src/libsync/theme.h +++ b/src/libsync/theme.h @@ -204,14 +204,6 @@ class OWNCLOUDSYNC_EXPORT Theme : public QObject * to nothing selected */ virtual bool wizardSelectiveSyncDefaultNothing() const; - /** - * @brief Add an additional checksum header to PUT requests and compare them - * if they come with GET requests. - * This value sets the checksum type (SHA1, MD5 or Adler32) or is left empty - * if no checksumming is wanted. In that case it can still be overwritten in - * the client config file. - */ - virtual QString transmissionChecksum() const; /** * Default option for the newBigFolderSizeLimit.