E2EE. Fix freeze on metadata checksum validation.

Signed-off-by: alex-z <blackslayer4@gmail.com>
This commit is contained in:
alex-z 2023-05-05 16:15:09 +02:00
parent c1bfd8b133
commit 90e3a37a20
7 changed files with 42 additions and 38 deletions

View file

@ -41,6 +41,7 @@ constexpr auto caCertsKeyC = "CaCertificates";
constexpr auto accountsC = "Accounts";
constexpr auto versionC = "version";
constexpr auto serverVersionC = "serverVersion";
constexpr auto skipE2eeMetadataChecksumValidationC = "skipE2eeMetadataChecksumValidation";
constexpr auto generalC = "General";
constexpr auto dummyAuthTypeC = "dummy";
@ -286,6 +287,11 @@ void AccountManager::saveAccountHelper(Account *acc, QSettings &settings, bool s
settings.setValue(QLatin1String(davUserC), acc->_davUser);
settings.setValue(QLatin1String(displayNameC), acc->_displayName);
settings.setValue(QLatin1String(serverVersionC), acc->_serverVersion);
if (!acc->_skipE2eeMetadataChecksumValidation) {
settings.remove(QLatin1String(skipE2eeMetadataChecksumValidationC));
} else {
settings.setValue(QLatin1String(skipE2eeMetadataChecksumValidationC), acc->_skipE2eeMetadataChecksumValidation);
}
if (acc->_credentials) {
if (saveCredentials) {
@ -385,6 +391,7 @@ AccountPtr AccountManager::loadAccountHelper(QSettings &settings)
qCInfo(lcAccountManager) << "Account for" << acc->url() << "using auth type" << authType;
acc->_serverVersion = settings.value(QLatin1String(serverVersionC)).toString();
acc->_skipE2eeMetadataChecksumValidation = settings.value(QLatin1String(skipE2eeMetadataChecksumValidationC), {}).toBool();
acc->_davUser = settings.value(QLatin1String(davUserC), "").toString();
// We want to only restore settings for that auth type and the user value

View file

@ -61,6 +61,7 @@ namespace {
constexpr int pushNotificationsReconnectInterval = 1000 * 60 * 2;
constexpr int usernamePrefillServerVersionMinSupportedMajor = 24;
constexpr int checksumRecalculateRequestServerVersionMinSupportedMajor = 24;
constexpr auto isSkipE2eeMetadataChecksumValidationAllowedInClientVersion = MIRALL_VERSION_MAJOR == 3 && MIRALL_VERSION_MINOR == 8;
}
namespace OCC {
@ -677,6 +678,17 @@ QString Account::serverVersion() const
return _serverVersion;
}
bool Account::shouldSkipE2eeMetadataChecksumValidation() const
{
return isSkipE2eeMetadataChecksumValidationAllowedInClientVersion && _skipE2eeMetadataChecksumValidation;
}
void Account::resetShouldSkipE2eeMetadataChecksumValidation()
{
_skipE2eeMetadataChecksumValidation = false;
emit wantsAccountSaved(this);
}
int Account::serverVersionInt() const
{
// FIXME: Use Qt 5.5 QVersionNumber

View file

@ -233,6 +233,10 @@ public:
*/
[[nodiscard]] QString serverVersion() const;
// 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();
/** Server version for easy comparison.
*
* Example: serverVersionInt() >= makeServerVersion(11, 2, 3)
@ -402,6 +406,7 @@ private:
QSslConfiguration _sslConfiguration;
Capabilities _capabilities;
QString _serverVersion;
bool _skipE2eeMetadataChecksumValidation = false;
QScopedPointer<AbstractSslErrorHandler> _sslErrorHandler;
QSharedPointer<QNetworkAccessManager> _am;
QScopedPointer<AbstractCredentials> _credentials;

View file

@ -1643,9 +1643,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 (_account->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
@ -1721,13 +1726,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;
}
@ -1748,31 +1746,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;

View file

@ -233,8 +233,6 @@ private:
[[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;

View file

@ -652,7 +652,11 @@ 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 && _account->shouldSkipE2eeMetadataChecksumValidation()) {
qCDebug(lcPropagator) << "Getting unexpected metadata format, but allowing to continue as shouldSkipE2eeMetadataChecksumValidation is set.";
} else if (isUnexpectedMetadataFormat && !_account->shouldSkipE2eeMetadataChecksumValidation()) {
qCDebug(lcPropagator) << "could have upgraded metadata";
item->_instruction = CSyncEnums::CSYNC_INSTRUCTION_ERROR;
item->_errorString = tr("Error with the metadata. Getting unexpected metadata format.");

View file

@ -956,6 +956,11 @@ void SyncEngine::finalize(bool success)
_syncRunning = false;
emit finished(success);
if (_account->shouldSkipE2eeMetadataChecksumValidation()) {
qCDebug(lcEngine) << "shouldSkipE2eeMetadataChecksumValidation was set. Sync is finished, so resetting it...";
_account->resetShouldSkipE2eeMetadataChecksumValidation();
}
// Delete the propagator only after emitting the signal.
_propagator.clear();
_seenConflictFiles.clear();