Skip to content

Commit

Permalink
E2EE. Fix freeze on metadata checksum validation.
Browse files Browse the repository at this point in the history
Signed-off-by: alex-z <blackslayer4@gmail.com>
  • Loading branch information
allexzander committed May 5, 2023
1 parent 19d796e commit 76da32d
Show file tree
Hide file tree
Showing 6 changed files with 40 additions and 38 deletions.
44 changes: 9 additions & 35 deletions src/libsync/clientsideencryption.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include "account.h"
#include "capabilities.h"
#include "configfile.h"
#include "networkjobs.h"
#include "clientsideencryptionjobs.h"
#include "theme.h"
Expand Down Expand Up @@ -1643,9 +1644,14 @@ void FolderMetadata::setupExistingMetadata(const QByteArray& metadata)

if (!migratedMetadata && !checkMetadataKeyChecksum(metadataKey, metadataKeyChecksum)) {
qCInfo(lcCseMetadata) << "checksum comparison failed" << "server value" << metadataKeyChecksum << "client value" << computeMetadataKeyChecksum(metadataKey);
_metadataKey.clear();
_files.clear();
return;
if (ConfigFile().shouldSkipE2eeMetadataChecksumValidation()) {
qCDebug(lcCseMetadata) << "shouldSkipE2eeMetadataChecksumValidation is set. Allowing invalid checksum until next sync.";
_encryptedMetadataNeedUpdate = true;
} else {
_metadataKey.clear();
_files.clear();
return;
}
}

// decryption finished, create new metadata key to be used for encryption
Expand Down Expand Up @@ -1721,13 +1727,6 @@ bool FolderMetadata::checkMetadataKeyChecksum(const QByteArray &metadataKey,
{
const auto referenceMetadataKeyValue = computeMetadataKeyChecksum(metadataKey);

if (referenceMetadataKeyValue != metadataKeyChecksum) {
if (recoverMetadataKeyChecksum(metadataKeyChecksum, metadataKey)) {
qCInfo(lcCseMetadata) << "Checksum recovery done";
return true;
}
}

return referenceMetadataKeyValue == metadataKeyChecksum;
}

Expand All @@ -1748,31 +1747,6 @@ QByteArray FolderMetadata::computeMetadataKeyChecksum(const QByteArray &metadata
return hashAlgorithm.result().toHex();
}

bool FolderMetadata::recoverMetadataKeyChecksum(const QByteArray &expectedChecksum,
const QByteArray &metadataKey) const
{
const auto sortLambda = [] (const auto &first, const auto &second) {
return first.encryptedFilename < second.encryptedFilename;
};
auto sortedFiles = _files;

std::sort(sortedFiles.begin(), sortedFiles.end(), sortLambda);

do {
auto hashAlgorithm = QCryptographicHash{QCryptographicHash::Sha256};
hashAlgorithm.addData(_account->e2e()->_mnemonic.remove(' ').toUtf8());
for (const auto &singleFile : sortedFiles) {
hashAlgorithm.addData(singleFile.encryptedFilename.toUtf8());
}
hashAlgorithm.addData(metadataKey);
if (hashAlgorithm.result().toHex() == expectedChecksum) {
return true;
}
} while (std::next_permutation(sortedFiles.begin(), sortedFiles.end(), sortLambda));

return false;
}

bool FolderMetadata::isMetadataSetup() const
{
return _isMetadataSetup;
Expand Down
2 changes: 0 additions & 2 deletions src/libsync/clientsideencryption.h
Original file line number Diff line number Diff line change
Expand Up @@ -233,8 +233,6 @@ class OWNCLOUDSYNC_EXPORT FolderMetadata {
[[nodiscard]] bool checkMetadataKeyChecksum(const QByteArray &metadataKey, const QByteArray &metadataKeyChecksum) const;

[[nodiscard]] QByteArray computeMetadataKeyChecksum(const QByteArray &metadataKey) const;
[[nodiscard]] bool recoverMetadataKeyChecksum(const QByteArray &expectedChecksum,
const QByteArray &metadataKey) const;

QByteArray _metadataKey;

Expand Down
15 changes: 15 additions & 0 deletions src/libsync/configfile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ static constexpr char updateChannelC[] = "updateChannel";
static constexpr char overrideServerUrlC[] = "overrideServerUrl";
static constexpr char overrideLocalDirC[] = "overrideLocalDir";
static constexpr char isVfsEnabledC[] = "isVfsEnabled";
static constexpr char skipE2eeMetadataChecksumValidation[] = "skipE2eeMetadataChecksumValidation";
static constexpr char geometryC[] = "geometry";
static constexpr char timeoutC[] = "timeout";
static constexpr char chunkSizeC[] = "chunkSize";
Expand Down Expand Up @@ -104,6 +105,7 @@ static constexpr char moveToTrashC[] = "moveToTrash";

static constexpr char certPath[] = "http_certificatePath";
static constexpr char certPasswd[] = "http_certificatePasswd";
static constexpr auto isSkipE2eeMetadataChecksumValidationAllowedInClientVersion = MIRALL_VERSION_MAJOR == 3 && MIRALL_VERSION_MINOR == 8;
}

namespace OCC {
Expand Down Expand Up @@ -731,6 +733,19 @@ bool ConfigFile::isVfsEnabled() const
return settings.value({isVfsEnabledC}, {}).toBool();
}

bool ConfigFile::shouldSkipE2eeMetadataChecksumValidation() const
{
QSettings settings(configFile(), QSettings::IniFormat);
return isSkipE2eeMetadataChecksumValidationAllowedInClientVersion
&& settings.value({skipE2eeMetadataChecksumValidation}, {}).toBool();
}

void ConfigFile::resetShouldSkipE2eeMetadataChecksumValidation()
{
QSettings settings(configFile(), QSettings::IniFormat);
settings.setValue({skipE2eeMetadataChecksumValidation}, false);
}

void ConfigFile::setVfsEnabled(bool enabled)
{
QSettings settings(configFile(), QSettings::IniFormat);
Expand Down
4 changes: 4 additions & 0 deletions src/libsync/configfile.h
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,10 @@ class OWNCLOUDSYNC_EXPORT ConfigFile
[[nodiscard]] bool isVfsEnabled() const;
void setVfsEnabled(bool enabled);

// check if the checksum validation of E2EE metadata is allowed to be skipped via config file, this will only work before client 3.9.0
[[nodiscard]] bool shouldSkipE2eeMetadataChecksumValidation() const;
void resetShouldSkipE2eeMetadataChecksumValidation();

void saveGeometryHeader(QHeaderView *header);
void restoreGeometryHeader(QHeaderView *header);

Expand Down
8 changes: 7 additions & 1 deletion src/libsync/owncloudpropagator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "common/utility.h"
#include "account.h"
#include "common/asserts.h"
#include "configfile.h"
#include "discoveryphase.h"
#include "syncfileitem.h"

Expand Down Expand Up @@ -652,7 +653,12 @@ void OwncloudPropagator::startDirectoryPropagation(const SyncFileItemPtr &item,
_anotherSyncNeeded = true;
} else if (item->_isEncryptedMetadataNeedUpdate) {
SyncJournalFileRecord record;
if (_journal->getFileRecord(item->_file, &record) && record._e2eEncryptionStatus == SyncJournalFileRecord::EncryptionStatus::EncryptedMigratedV1_2) {
const auto isUnexpectedMetadataFormat = _journal->getFileRecord(item->_file, &record)
&& record._e2eEncryptionStatus == SyncJournalFileRecord::EncryptionStatus::EncryptedMigratedV1_2;
if (isUnexpectedMetadataFormat && ConfigFile().shouldSkipE2eeMetadataChecksumValidation()) {
qCDebug(lcPropagator) << "Getting unexpected metadata format, but allowing to continue as shouldSkipE2eeMetadataChecksumValidation is set.";
}
if (isUnexpectedMetadataFormat && !ConfigFile().shouldSkipE2eeMetadataChecksumValidation()) {
qCDebug(lcPropagator) << "could have upgraded metadata";
item->_instruction = CSyncEnums::CSYNC_INSTRUCTION_ERROR;
item->_errorString = tr("Error with the metadata. Getting unexpected metadata format.");
Expand Down
5 changes: 5 additions & 0 deletions src/libsync/syncengine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -956,6 +956,11 @@ void SyncEngine::finalize(bool success)
_syncRunning = false;
emit finished(success);

if (ConfigFile().shouldSkipE2eeMetadataChecksumValidation()) {
qCDebug(lcEngine) << "shouldSkipE2eeMetadataChecksumValidation was set. Sync is finished, so resetting it...";
ConfigFile().resetShouldSkipE2eeMetadataChecksumValidation();
}

// Delete the propagator only after emitting the signal.
_propagator.clear();
_seenConflictFiles.clear();
Expand Down

0 comments on commit 76da32d

Please sign in to comment.