From 8659df22664eeedf33986fe91246d44fe2b3d8f8 Mon Sep 17 00:00:00 2001 From: Matthieu Gallien Date: Wed, 29 Mar 2023 12:42:11 +0200 Subject: [PATCH] prevent downgrading e2ee metadata format after initial migration Signed-off-by: Matthieu Gallien --- src/common/syncjournaldb.cpp | 10 +++++-- src/common/syncjournalfilerecord.h | 12 +++++++-- src/libsync/clientsideencryption.cpp | 27 +++++++++++++++++-- src/libsync/clientsideencryption.h | 17 +++++++++++- src/libsync/discovery.cpp | 5 ++-- src/libsync/discoveryphase.cpp | 14 ++++++++-- src/libsync/discoveryphase.h | 6 +++-- src/libsync/encryptfolderjob.cpp | 2 +- src/libsync/owncloudpropagator.cpp | 2 +- src/libsync/propagatedownloadencrypted.cpp | 4 ++- .../propagateremotedeleteencrypted.cpp | 4 ++- ...opagateremotedeleteencryptedrootfolder.cpp | 4 ++- src/libsync/propagateremotemkdir.cpp | 2 +- src/libsync/propagateuploadencrypted.cpp | 6 +++-- src/libsync/syncfileitem.cpp | 6 ++--- src/libsync/syncfileitem.h | 14 +++++++--- src/libsync/updatefiledropmetadata.cpp | 6 +++-- test/testfolderman.cpp | 2 +- test/testsecurefiledrop.cpp | 4 +-- 19 files changed, 115 insertions(+), 32 deletions(-) diff --git a/src/common/syncjournaldb.cpp b/src/common/syncjournaldb.cpp index 2a91a8f79..9aad5599b 100644 --- a/src/common/syncjournaldb.cpp +++ b/src/common/syncjournaldb.cpp @@ -66,7 +66,7 @@ static void fillFileRecordFromGetQuery(SyncJournalFileRecord &rec, SqlQuery &que rec._serverHasIgnoredFiles = (query.intValue(8) > 0); rec._checksumHeader = query.baValue(9); rec._e2eMangledName = query.baValue(10); - rec._isE2eEncrypted = query.intValue(11) > 0; + rec._isE2eEncrypted = static_cast(query.intValue(11)); rec._lockstate._locked = query.intValue(12) > 0; rec._lockstate._lockOwnerDisplayName = query.stringValue(13); rec._lockstate._lockOwnerId = query.stringValue(14); @@ -968,7 +968,7 @@ Result SyncJournalDb::setFileRecord(const SyncJournalFileRecord & query->bindValue(15, checksum); query->bindValue(16, contentChecksumTypeId); query->bindValue(17, record._e2eMangledName); - query->bindValue(18, record.isE2eEncrypted()); + query->bindValue(18, static_cast(record._isE2eEncrypted)); query->bindValue(19, record._lockstate._locked ? 1 : 0); query->bindValue(20, record._lockstate._lockOwnerType); query->bindValue(21, record._lockstate._lockOwnerDisplayName); @@ -2694,4 +2694,10 @@ bool operator==(const SyncJournalDb::UploadInfo &lhs, && lhs._contentChecksum == rhs._contentChecksum; } +QDebug& operator<<(QDebug &stream, const SyncJournalFileRecord::EncryptionStatus status) +{ + stream << static_cast(status); + return stream; +} + } // namespace OCC diff --git a/src/common/syncjournalfilerecord.h b/src/common/syncjournalfilerecord.h index f32e4c588..4daaf1120 100644 --- a/src/common/syncjournalfilerecord.h +++ b/src/common/syncjournalfilerecord.h @@ -53,6 +53,12 @@ public: return !_path.isEmpty(); } + enum class EncryptionStatus : int { + NotEncrypted = 0, + Encrypted = 1, + EncryptedMigratedV1_2 = 2, + }; + /** Returns the numeric part of the full id in _fileId. * * On the server this is sometimes known as the internal file id. @@ -67,7 +73,7 @@ public: [[nodiscard]] bool isVirtualFile() const { return _type == ItemTypeVirtualFile || _type == ItemTypeVirtualFileDownload; } [[nodiscard]] QString path() const { return QString::fromUtf8(_path); } [[nodiscard]] QString e2eMangledName() const { return QString::fromUtf8(_e2eMangledName); } - [[nodiscard]] bool isE2eEncrypted() const { return _isE2eEncrypted; } + [[nodiscard]] bool isE2eEncrypted() const { return _isE2eEncrypted != SyncJournalFileRecord::EncryptionStatus::NotEncrypted; } QByteArray _path; quint64 _inode = 0; @@ -80,13 +86,15 @@ public: bool _serverHasIgnoredFiles = false; QByteArray _checksumHeader; QByteArray _e2eMangledName; - bool _isE2eEncrypted = false; + EncryptionStatus _isE2eEncrypted = EncryptionStatus::NotEncrypted; SyncJournalFileLockInfo _lockstate; bool _isShared = false; qint64 _lastShareStateFetchedTimestamp = 0; bool _sharedByMe = false; }; +QDebug& operator<<(QDebug &stream, const SyncJournalFileRecord::EncryptionStatus status); + bool OCSYNC_EXPORT operator==(const SyncJournalFileRecord &lhs, const SyncJournalFileRecord &rhs); diff --git a/src/libsync/clientsideencryption.cpp b/src/libsync/clientsideencryption.cpp index 04bd0f0b3..16f121e18 100644 --- a/src/libsync/clientsideencryption.cpp +++ b/src/libsync/clientsideencryption.cpp @@ -1498,7 +1498,19 @@ void ClientSideEncryption::fetchAndValidatePublicKeyFromServer(const AccountPtr job->start(); } -FolderMetadata::FolderMetadata(AccountPtr account, const QByteArray& metadata, int statusCode) : _account(account) +FolderMetadata::FolderMetadata(AccountPtr account) + : _account(account) +{ + qCInfo(lcCseMetadata()) << "Setupping Empty Metadata"; + setupEmptyMetadata(); +} + +FolderMetadata::FolderMetadata(AccountPtr account, + RequiredMetadataVersion requiredMetadataVersion, + const QByteArray& metadata, + int statusCode) + : _account(account) + , _requiredMetadataVersion(requiredMetadataVersion) { if (metadata.isEmpty() || statusCode == 404) { qCInfo(lcCseMetadata()) << "Setupping Empty Metadata"; @@ -1541,7 +1553,7 @@ void FolderMetadata::setupExistingMetadata(const QByteArray& metadata) } auto migratedMetadata = false; - if (_metadataKey.isEmpty()) { + if (_metadataKey.isEmpty() && _requiredMetadataVersion != RequiredMetadataVersion::Version1_2) { qCDebug(lcCse()) << "Migrating from v1.1 to v1.2"; migratedMetadata = true; @@ -1618,6 +1630,8 @@ void FolderMetadata::setupExistingMetadata(const QByteArray& metadata) file.mimetype = QByteArrayLiteral("httpd/unix-directory"); } + qCDebug(lcCseMetadata) << "encrypted file" << decryptedFileObj["filename"].toString() << decryptedFileObj["key"].toString() << it.key(); + _files.push_back(file); } @@ -1631,6 +1645,10 @@ void FolderMetadata::setupExistingMetadata(const QByteArray& metadata) // decryption finished, create new metadata key to be used for encryption _metadataKey = EncryptionHelper::generateRandom(metadataKeySize); _isMetadataSetup = true; + + if (migratedMetadata) { + _encryptedMetadataNeedUpdate = true; + } } // RSA/ECB/OAEPWithSHA-256AndMGF1Padding using private / public key. @@ -1792,6 +1810,11 @@ bool FolderMetadata::isFileDropPresent() const return _fileDrop.size() > 0; } +bool FolderMetadata::encryptedMetadataNeedUpdate() const +{ + return _encryptedMetadataNeedUpdate; +} + bool FolderMetadata::moveFromFileDropToFiles() { if (_fileDrop.isEmpty()) { diff --git a/src/libsync/clientsideencryption.h b/src/libsync/clientsideencryption.h index a180ef78f..811dd8edb 100644 --- a/src/libsync/clientsideencryption.h +++ b/src/libsync/clientsideencryption.h @@ -186,7 +186,18 @@ struct EncryptedFile { class OWNCLOUDSYNC_EXPORT FolderMetadata { public: - FolderMetadata(AccountPtr account, const QByteArray& metadata = QByteArray(), int statusCode = -1); + enum class RequiredMetadataVersion { + Version1, + Version1_2, + }; + + explicit FolderMetadata(AccountPtr account); + + explicit FolderMetadata(AccountPtr account, + RequiredMetadataVersion requiredMetadataVersion, + const QByteArray& metadata, + int statusCode = -1); + [[nodiscard]] QByteArray encryptedMetadata() const; void addEncryptedFile(const EncryptedFile& f); void removeEncryptedFile(const EncryptedFile& f); @@ -196,6 +207,8 @@ public: [[nodiscard]] bool isFileDropPresent() const; + [[nodiscard]] bool encryptedMetadataNeedUpdate() const; + [[nodiscard]] bool moveFromFileDropToFiles(); [[nodiscard]] QJsonObject fileDrop() const; @@ -221,9 +234,11 @@ private: QVector _files; AccountPtr _account; + RequiredMetadataVersion _requiredMetadataVersion = RequiredMetadataVersion::Version1_2; QVector> _sharing; QJsonObject _fileDrop; bool _isMetadataSetup = false; + bool _encryptedMetadataNeedUpdate = false; }; } // namespace OCC diff --git a/src/libsync/discovery.cpp b/src/libsync/discovery.cpp index c9aa2d02a..fea387865 100644 --- a/src/libsync/discovery.cpp +++ b/src/libsync/discovery.cpp @@ -532,7 +532,7 @@ void ProcessDirectoryJob::processFileAnalyzeRemoteInfo( item->_etag = serverEntry.etag; item->_directDownloadUrl = serverEntry.directDownloadUrl; item->_directDownloadCookies = serverEntry.directDownloadCookies; - item->_isEncrypted = serverEntry.isE2eEncrypted(); + item->_isEncrypted = serverEntry.isE2eEncrypted() ? SyncFileItem::EncryptionStatus::EncryptedMigratedV1_2 : SyncFileItem::EncryptionStatus::NotEncrypted; item->_encryptedFileName = [=] { if (serverEntry.e2eMangledName.isEmpty()) { return QString(); @@ -1292,7 +1292,7 @@ void ProcessDirectoryJob::processFileAnalyzeLocalInfo( if (base.isE2eEncrypted()) { // renaming the encrypted folder is done via remove + re-upload hence we need to mark the newly created folder as encrypted // base is a record in the SyncJournal database that contains the data about the being-renamed folder with it's old name and encryption information - item->_isEncrypted = true; + item->_isEncrypted = SyncFileItem::EncryptionStatus::EncryptedMigratedV1_2; } postProcessLocalNew(); finalize(); @@ -1850,6 +1850,7 @@ DiscoverySingleDirectoryJob *ProcessDirectoryJob::startAsyncServerQuery() connect(serverJob, &DiscoverySingleDirectoryJob::finished, this, [this, serverJob](const auto &results) { if (_dirItem) { _dirItem->_isFileDropDetected = serverJob->isFileDropDetected(); + _dirItem->_isEncryptedMetadataNeedUpdate = serverJob->encryptedMetadataNeedUpdate(); qCInfo(lcDisco) << "serverJob has finished for folder:" << _dirItem->_file << " and it has _isFileDropDetected:" << true; } _discoveryData->_currentlyActiveJobs--; diff --git a/src/libsync/discoveryphase.cpp b/src/libsync/discoveryphase.cpp index dc327b237..54e8e4c38 100644 --- a/src/libsync/discoveryphase.cpp +++ b/src/libsync/discoveryphase.cpp @@ -410,6 +410,11 @@ bool DiscoverySingleDirectoryJob::isFileDropDetected() const return _isFileDropDetected; } +bool DiscoverySingleDirectoryJob::encryptedMetadataNeedUpdate() const +{ + return _encryptedMetadataNeedUpdate; +} + static void propertyMapToRemoteInfo(const QMap &map, RemoteInfo &result) { for (auto it = map.constBegin(); it != map.constEnd(); ++it) { @@ -530,7 +535,7 @@ void DiscoverySingleDirectoryJob::directoryListingIteratedSlot(const QString &fi _fileId = map.value("id").toUtf8(); } if (map.contains("is-encrypted") && map.value("is-encrypted") == QStringLiteral("1")) { - _isE2eEncrypted = true; + _isE2eEncrypted = SyncFileItem::EncryptionStatus::Encrypted; Q_ASSERT(!_fileId.isEmpty()); } if (map.contains("size")) { @@ -621,8 +626,13 @@ void DiscoverySingleDirectoryJob::metadataReceived(const QJsonDocument &json, in qCDebug(lcDiscovery) << "Metadata received, applying it to the result list"; Q_ASSERT(_subPath.startsWith('/')); - const auto metadata = FolderMetadata(_account, json.toJson(QJsonDocument::Compact), statusCode); + const auto metadata = FolderMetadata(_account, + _isE2eEncrypted == SyncFileItem::EncryptionStatus::EncryptedMigratedV1_2 ? FolderMetadata::RequiredMetadataVersion::Version1_2 : FolderMetadata::RequiredMetadataVersion::Version1, + json.toJson(QJsonDocument::Compact), + statusCode); _isFileDropDetected = metadata.isFileDropPresent(); + _encryptedMetadataNeedUpdate = metadata.encryptedMetadataNeedUpdate(); + const auto encryptedFiles = metadata.files(); const auto findEncryptedFile = [=](const QString &name) { diff --git a/src/libsync/discoveryphase.h b/src/libsync/discoveryphase.h index 5f5a4223e..c833fd719 100644 --- a/src/libsync/discoveryphase.h +++ b/src/libsync/discoveryphase.h @@ -145,6 +145,7 @@ public: void start(); void abort(); [[nodiscard]] bool isFileDropDetected() const; + [[nodiscard]] bool encryptedMetadataNeedUpdate() const; // This is not actually a network job, it is just a job signals: @@ -162,7 +163,7 @@ private slots: private: - [[nodiscard]] bool isE2eEncrypted() const { return _isE2eEncrypted; } + [[nodiscard]] bool isE2eEncrypted() const { return _isE2eEncrypted != SyncFileItem::EncryptionStatus::NotEncrypted; } QVector _results; QString _subPath; @@ -178,8 +179,9 @@ private: // If this directory is an external storage (The first item has 'M' in its permission) bool _isExternalStorage = false; // If this directory is e2ee - bool _isE2eEncrypted = false; + SyncFileItem::EncryptionStatus _isE2eEncrypted = SyncFileItem::EncryptionStatus::NotEncrypted; bool _isFileDropDetected = false; + bool _encryptedMetadataNeedUpdate = false; // If set, the discovery will finish with an error int64_t _size = 0; QString _error; diff --git a/src/libsync/encryptfolderjob.cpp b/src/libsync/encryptfolderjob.cpp index 033199ba3..99a502985 100644 --- a/src/libsync/encryptfolderjob.cpp +++ b/src/libsync/encryptfolderjob.cpp @@ -56,7 +56,7 @@ void EncryptFolderJob::slotEncryptionFlagSuccess(const QByteArray &fileId) qCWarning(lcEncryptFolderJob) << "No valid record found in local DB for fileId" << fileId; } - rec._isE2eEncrypted = true; + rec._isE2eEncrypted = SyncJournalFileRecord::EncryptionStatus::EncryptedMigratedV1_2; const auto result = _journal->setFileRecord(rec); if (!result) { qCWarning(lcEncryptFolderJob) << "Error when setting the file record to the database" << rec._path << result.error(); diff --git a/src/libsync/owncloudpropagator.cpp b/src/libsync/owncloudpropagator.cpp index 51510ad88..15567d680 100644 --- a/src/libsync/owncloudpropagator.cpp +++ b/src/libsync/owncloudpropagator.cpp @@ -646,7 +646,7 @@ void OwncloudPropagator::startDirectoryPropagation(const SyncFileItemPtr &item, const auto currentDirJob = directories.top().second; currentDirJob->appendJob(directoryPropagationJob.get()); } - if (item->_isFileDropDetected) { + if (item->_isFileDropDetected || item->_isEncryptedMetadataNeedUpdate) { directoryPropagationJob->appendJob(new UpdateFileDropMetadataJob(this, item->_file)); item->_instruction = CSYNC_INSTRUCTION_NONE; _anotherSyncNeeded = true; diff --git a/src/libsync/propagatedownloadencrypted.cpp b/src/libsync/propagatedownloadencrypted.cpp index 77aadbce9..9788d5cf1 100644 --- a/src/libsync/propagatedownloadencrypted.cpp +++ b/src/libsync/propagatedownloadencrypted.cpp @@ -73,7 +73,9 @@ void PropagateDownloadEncrypted::checkFolderEncryptedMetadata(const QJsonDocumen qCDebug(lcPropagateDownloadEncrypted) << "Metadata Received reading" << _item->_instruction << _item->_file << _item->_encryptedFileName; const QString filename = _info.fileName(); - const FolderMetadata metadata(_propagator->account(), json.toJson(QJsonDocument::Compact)); + const FolderMetadata metadata(_propagator->account(), + _item->_isEncrypted == SyncFileItem::EncryptionStatus::EncryptedMigratedV1_2 ? FolderMetadata::RequiredMetadataVersion::Version1_2 : FolderMetadata::RequiredMetadataVersion::Version1, + json.toJson(QJsonDocument::Compact)); if (metadata.isMetadataSetup()) { const QVector files = metadata.files(); diff --git a/src/libsync/propagateremotedeleteencrypted.cpp b/src/libsync/propagateremotedeleteencrypted.cpp index 1d7ae8aa6..ee1b57dee 100644 --- a/src/libsync/propagateremotedeleteencrypted.cpp +++ b/src/libsync/propagateremotedeleteencrypted.cpp @@ -51,7 +51,9 @@ void PropagateRemoteDeleteEncrypted::slotFolderEncryptedMetadataReceived(const Q return; } - FolderMetadata metadata(_propagator->account(), json.toJson(QJsonDocument::Compact), statusCode); + FolderMetadata metadata(_propagator->account(), + _item->_isEncrypted == SyncFileItem::EncryptionStatus::EncryptedMigratedV1_2 ? FolderMetadata::RequiredMetadataVersion::Version1_2 : FolderMetadata::RequiredMetadataVersion::Version1, + json.toJson(QJsonDocument::Compact), statusCode); if (!metadata.isMetadataSetup()) { taskFailed(); diff --git a/src/libsync/propagateremotedeleteencryptedrootfolder.cpp b/src/libsync/propagateremotedeleteencryptedrootfolder.cpp index c9f82ee8e..5cae505ff 100644 --- a/src/libsync/propagateremotedeleteencryptedrootfolder.cpp +++ b/src/libsync/propagateremotedeleteencryptedrootfolder.cpp @@ -81,7 +81,9 @@ void PropagateRemoteDeleteEncryptedRootFolder::slotFolderEncryptedMetadataReceiv return; } - FolderMetadata metadata(_propagator->account(), json.toJson(QJsonDocument::Compact), statusCode); + FolderMetadata metadata(_propagator->account(), + _item->_isEncrypted == SyncFileItem::EncryptionStatus::EncryptedMigratedV1_2 ? FolderMetadata::RequiredMetadataVersion::Version1_2 : FolderMetadata::RequiredMetadataVersion::Version1, + json.toJson(QJsonDocument::Compact), statusCode); if (!metadata.isMetadataSetup()) { taskFailed(); diff --git a/src/libsync/propagateremotemkdir.cpp b/src/libsync/propagateremotemkdir.cpp index b4dc65b97..82a09c0d7 100644 --- a/src/libsync/propagateremotemkdir.cpp +++ b/src/libsync/propagateremotemkdir.cpp @@ -243,7 +243,7 @@ void PropagateRemoteMkdir::slotEncryptFolderFinished() { qCDebug(lcPropagateRemoteMkdir) << "Success making the new folder encrypted"; propagator()->_activeJobList.removeOne(this); - _item->_isEncrypted = true; + _item->_isEncrypted = SyncFileItem::EncryptionStatus::EncryptedMigratedV1_2; success(); } diff --git a/src/libsync/propagateuploadencrypted.cpp b/src/libsync/propagateuploadencrypted.cpp index f027c1c8a..ad2eff35c 100644 --- a/src/libsync/propagateuploadencrypted.cpp +++ b/src/libsync/propagateuploadencrypted.cpp @@ -121,7 +121,9 @@ void PropagateUploadEncrypted::slotFolderEncryptedMetadataReceived(const QJsonDo qCDebug(lcPropagateUploadEncrypted) << "Metadata Received, Preparing it for the new file." << json.toVariant(); // Encrypt File! - _metadata.reset(new FolderMetadata(_propagator->account(), json.toJson(QJsonDocument::Compact), statusCode)); + _metadata.reset(new FolderMetadata(_propagator->account(), + _item->_isEncrypted == SyncFileItem::EncryptionStatus::EncryptedMigratedV1_2 ? FolderMetadata::RequiredMetadataVersion::Version1_2 : FolderMetadata::RequiredMetadataVersion::Version1, + json.toJson(QJsonDocument::Compact), statusCode)); if (!_metadata->isMetadataSetup()) { if (_isFolderLocked) { @@ -169,7 +171,7 @@ void PropagateUploadEncrypted::slotFolderEncryptedMetadataReceived(const QJsonDo encryptedFile.initializationVector = EncryptionHelper::generateRandom(16); _item->_encryptedFileName = _remoteParentPath + QLatin1Char('/') + encryptedFile.encryptedFilename; - _item->_isEncrypted = true; + _item->_isEncrypted = SyncFileItem::EncryptionStatus::EncryptedMigratedV1_2; qCDebug(lcPropagateUploadEncrypted) << "Creating the encrypted file."; diff --git a/src/libsync/syncfileitem.cpp b/src/libsync/syncfileitem.cpp index 135f3c637..ee2805e72 100644 --- a/src/libsync/syncfileitem.cpp +++ b/src/libsync/syncfileitem.cpp @@ -49,7 +49,7 @@ SyncJournalFileRecord SyncFileItem::toSyncJournalFileRecordWithInode(const QStri rec._serverHasIgnoredFiles = _serverHasIgnoredFiles; rec._checksumHeader = _checksumHeader; rec._e2eMangledName = _encryptedFileName.toUtf8(); - rec._isE2eEncrypted = isEncrypted(); + rec._isE2eEncrypted = isEncrypted() ? SyncJournalFileRecord::EncryptionStatus::EncryptedMigratedV1_2 : SyncJournalFileRecord::EncryptionStatus::NotEncrypted; rec._lockstate._locked = _locked == LockStatus::LockedItem; rec._lockstate._lockOwnerDisplayName = _lockOwnerDisplayName; rec._lockstate._lockOwnerId = _lockOwnerId; @@ -86,7 +86,7 @@ SyncFileItemPtr SyncFileItem::fromSyncJournalFileRecord(const SyncJournalFileRec item->_serverHasIgnoredFiles = rec._serverHasIgnoredFiles; item->_checksumHeader = rec._checksumHeader; item->_encryptedFileName = rec.e2eMangledName(); - item->_isEncrypted = rec.isE2eEncrypted(); + item->_isEncrypted = static_cast(rec._isE2eEncrypted); item->_locked = rec._lockstate._locked ? LockStatus::LockedItem : LockStatus::UnlockedItem; item->_lockOwnerDisplayName = rec._lockstate._lockOwnerDisplayName; item->_lockOwnerId = rec._lockstate._lockOwnerId; @@ -123,7 +123,7 @@ SyncFileItemPtr SyncFileItem::fromProperties(const QString &filePath, const QMap item->_isShared = item->_remotePerm.hasPermission(RemotePermissions::IsShared); item->_lastShareStateFetchedTimestamp = QDateTime::currentMSecsSinceEpoch(); - item->_isEncrypted = properties.value(QStringLiteral("is-encrypted")) == QStringLiteral("1"); + item->_isEncrypted = (properties.value(QStringLiteral("is-encrypted")) == QStringLiteral("1") ? SyncFileItem::EncryptionStatus::EncryptedMigratedV1_2 : SyncFileItem::EncryptionStatus::NotEncrypted); item->_locked = properties.value(QStringLiteral("lock")) == QStringLiteral("1") ? SyncFileItem::LockStatus::LockedItem : SyncFileItem::LockStatus::UnlockedItem; item->_lockOwnerDisplayName = properties.value(QStringLiteral("lock-owner-displayname")); diff --git a/src/libsync/syncfileitem.h b/src/libsync/syncfileitem.h index 4715901ab..f888ec6d4 100644 --- a/src/libsync/syncfileitem.h +++ b/src/libsync/syncfileitem.h @@ -46,6 +46,13 @@ public: }; Q_ENUM(Direction) + enum class EncryptionStatus : int { + NotEncrypted = 0, + Encrypted = 1, + EncryptedMigratedV1_2 = 2, + }; + Q_ENUM(EncryptionStatus) + // Note: the order of these statuses is used for ordering in the SortedActivityListModel enum Status { // stored in 4 bits NoStatus, @@ -138,7 +145,6 @@ public: , _status(NoStatus) , _isRestoration(false) , _isSelectiveSync(false) - , _isEncrypted(false) { } @@ -228,7 +234,7 @@ public: && !(_instruction == CSYNC_INSTRUCTION_CONFLICT && _status == SyncFileItem::Success); } - [[nodiscard]] bool isEncrypted() const { return _isEncrypted; } + [[nodiscard]] bool isEncrypted() const { return _isEncrypted != SyncFileItem::EncryptionStatus::NotEncrypted; } // Variables useful for everybody @@ -275,7 +281,7 @@ public: Status _status BITFIELD(4); bool _isRestoration BITFIELD(1); // The original operation was forbidden, and this is a restoration bool _isSelectiveSync BITFIELD(1); // The file is removed or ignored because it is in the selective sync list - bool _isEncrypted BITFIELD(1); // The file is E2EE or the content of the directory should be E2EE + EncryptionStatus _isEncrypted = EncryptionStatus::NotEncrypted; // The file is E2EE or the content of the directory should be E2EE quint16 _httpErrorCode = 0; RemotePermissions _remotePerm; QString _errorString; // Contains a string only in case of error @@ -321,6 +327,8 @@ public: bool _sharedByMe = false; bool _isFileDropDetected = false; + + bool _isEncryptedMetadataNeedUpdate = false; }; inline bool operator<(const SyncFileItemPtr &item1, const SyncFileItemPtr &item2) diff --git a/src/libsync/updatefiledropmetadata.cpp b/src/libsync/updatefiledropmetadata.cpp index 0d23f2f70..02103a093 100644 --- a/src/libsync/updatefiledropmetadata.cpp +++ b/src/libsync/updatefiledropmetadata.cpp @@ -122,8 +122,10 @@ void UpdateFileDropMetadataJob::slotFolderEncryptedMetadataReceived(const QJsonD qCDebug(lcUpdateFileDropMetadataJob) << "Metadata Received, Preparing it for the new file." << json.toVariant(); // Encrypt File! - _metadata.reset(new FolderMetadata(propagator()->account(), json.toJson(QJsonDocument::Compact), statusCode)); - if (!_metadata->moveFromFileDropToFiles()) { + _metadata.reset(new FolderMetadata(propagator()->account(), + FolderMetadata::RequiredMetadataVersion::Version1, + json.toJson(QJsonDocument::Compact), statusCode)); + if (!_metadata->moveFromFileDropToFiles() && !_metadata->encryptedMetadataNeedUpdate()) { unlockFolder(); return; } diff --git a/test/testfolderman.cpp b/test/testfolderman.cpp index 2cd2afd49..db9b7d40a 100644 --- a/test/testfolderman.cpp +++ b/test/testfolderman.cpp @@ -123,7 +123,7 @@ private slots: // the server, let's just manually set the encryption bool in the folder journal SyncJournalFileRecord rec; QVERIFY(folder->journalDb()->getFileRecord(QStringLiteral("encrypted"), &rec)); - rec._isE2eEncrypted = true; + rec._isE2eEncrypted = SyncJournalFileRecord::EncryptionStatus::EncryptedMigratedV1_2; rec._path = QStringLiteral("encrypted").toUtf8(); rec._type = CSyncEnums::ItemTypeDirectory; QVERIFY(folder->journalDb()->setFileRecord(rec)); diff --git a/test/testsecurefiledrop.cpp b/test/testsecurefiledrop.cpp index 33653b800..dd0a6ac00 100644 --- a/test/testsecurefiledrop.cpp +++ b/test/testsecurefiledrop.cpp @@ -69,8 +69,8 @@ private slots: QFile fakeJsonReplyFile(QStringLiteral("fakefiledrope2eefoldermetadata.json")); if (fakeJsonReplyFile.open(QFile::ReadOnly)) { const auto jsonDoc = QJsonDocument::fromJson(fakeJsonReplyFile.readAll()); - _parsedMetadataWithFileDrop.reset(new FolderMetadata(_fakeFolder.syncEngine().account(), jsonDoc.toJson())); - _parsedMetadataAfterProcessingFileDrop.reset(new FolderMetadata(_fakeFolder.syncEngine().account(), jsonDoc.toJson())); + _parsedMetadataWithFileDrop.reset(new FolderMetadata(_fakeFolder.syncEngine().account(), FolderMetadata::RequiredMetadataVersion::Version1_2, jsonDoc.toJson())); + _parsedMetadataAfterProcessingFileDrop.reset(new FolderMetadata(_fakeFolder.syncEngine().account(), FolderMetadata::RequiredMetadataVersion::Version1_2, jsonDoc.toJson())); [[maybe_unused]] const auto result = _parsedMetadataAfterProcessingFileDrop->moveFromFileDropToFiles(); reply = new FakePayloadReply(op, req, jsonDoc.toJson(), nullptr); ++_getMetadataCallsCount;