Skip to content

Commit

Permalink
Merge pull request #5599 from nextcloud/backport/5577/stable-3.8
Browse files Browse the repository at this point in the history
[stable-3.8] properly preserve the format of e2ee metadata during DB operations
  • Loading branch information
mgallien authored Apr 13, 2023
2 parents 727b767 + 6f0ac4c commit 985f50a
Show file tree
Hide file tree
Showing 14 changed files with 97 additions and 31 deletions.
4 changes: 2 additions & 2 deletions src/common/syncjournaldb.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 = static_cast<SyncJournalFileRecord::EncryptionStatus>(query.intValue(11));
rec._e2eEncryptionStatus = static_cast<SyncJournalFileRecord::EncryptionStatus>(query.intValue(11));
rec._lockstate._locked = query.intValue(12) > 0;
rec._lockstate._lockOwnerDisplayName = query.stringValue(13);
rec._lockstate._lockOwnerId = query.stringValue(14);
Expand Down Expand Up @@ -968,7 +968,7 @@ Result<void, QString> SyncJournalDb::setFileRecord(const SyncJournalFileRecord &
query->bindValue(15, checksum);
query->bindValue(16, contentChecksumTypeId);
query->bindValue(17, record._e2eMangledName);
query->bindValue(18, static_cast<int>(record._isE2eEncrypted));
query->bindValue(18, static_cast<int>(record._e2eEncryptionStatus));
query->bindValue(19, record._lockstate._locked ? 1 : 0);
query->bindValue(20, record._lockstate._lockOwnerType);
query->bindValue(21, record._lockstate._lockOwnerDisplayName);
Expand Down
10 changes: 3 additions & 7 deletions src/common/syncjournalfilerecord.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,7 @@ class OCSYNC_EXPORT SyncJournalFileRecord
return !_path.isEmpty();
}

enum class EncryptionStatus : int {
NotEncrypted = 0,
Encrypted = 1,
EncryptedMigratedV1_2 = 2,
};
using EncryptionStatus = EncryptionStatusEnums::JournalDbEncryptionStatus;

/** Returns the numeric part of the full id in _fileId.
*
Expand All @@ -73,7 +69,7 @@ class OCSYNC_EXPORT SyncJournalFileRecord
[[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 != SyncJournalFileRecord::EncryptionStatus::NotEncrypted; }
[[nodiscard]] bool isE2eEncrypted() const { return _e2eEncryptionStatus != EncryptionStatus::NotEncrypted; }

QByteArray _path;
quint64 _inode = 0;
Expand All @@ -86,7 +82,7 @@ class OCSYNC_EXPORT SyncJournalFileRecord
bool _serverHasIgnoredFiles = false;
QByteArray _checksumHeader;
QByteArray _e2eMangledName;
EncryptionStatus _isE2eEncrypted = EncryptionStatus::NotEncrypted;
EncryptionStatus _e2eEncryptionStatus = EncryptionStatus::NotEncrypted;
SyncJournalFileLockInfo _lockstate;
bool _isShared = false;
qint64 _lastShareStateFetchedTimestamp = 0;
Expand Down
28 changes: 28 additions & 0 deletions src/csync/csync.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,34 @@

namespace OCC {
class SyncJournalFileRecord;

namespace EncryptionStatusEnums {

Q_NAMESPACE

enum class ItemEncryptionStatus : int {
NotEncrypted = 0,
Encrypted = 1,
EncryptedMigratedV1_2 = 2,
};

Q_ENUM_NS(ItemEncryptionStatus)

enum class JournalDbEncryptionStatus : int {
NotEncrypted = 0,
Encrypted = 1,
EncryptedMigratedV1_2Invalid = 2,
EncryptedMigratedV1_2 = 3,
};

Q_ENUM_NS(JournalDbEncryptionStatus)

ItemEncryptionStatus fromDbEncryptionStatus(JournalDbEncryptionStatus encryptionStatus);

JournalDbEncryptionStatus toDbEncryptionStatus(ItemEncryptionStatus encryptionStatus);

}

}

#if defined(Q_CC_GNU) && !defined(Q_CC_INTEL) && !defined(Q_CC_CLANG) && (__GNUC__ * 100 + __GNUC_MINOR__ < 408)
Expand Down
4 changes: 2 additions & 2 deletions src/libsync/discovery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -532,7 +532,7 @@ void ProcessDirectoryJob::processFileAnalyzeRemoteInfo(
item->_etag = serverEntry.etag;
item->_directDownloadUrl = serverEntry.directDownloadUrl;
item->_directDownloadCookies = serverEntry.directDownloadCookies;
item->_isEncrypted = serverEntry.isE2eEncrypted() ? SyncFileItem::EncryptionStatus::Encrypted : SyncFileItem::EncryptionStatus::NotEncrypted;
item->_e2eEncryptionStatus = serverEntry.isE2eEncrypted() ? SyncFileItem::EncryptionStatus::Encrypted : SyncFileItem::EncryptionStatus::NotEncrypted;
item->_encryptedFileName = [=] {
if (serverEntry.e2eMangledName.isEmpty()) {
return QString();
Expand Down Expand Up @@ -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 = static_cast<SyncFileItem::EncryptionStatus>(base._isE2eEncrypted);
item->_e2eEncryptionStatus = EncryptionStatusEnums::fromDbEncryptionStatus(base._e2eEncryptionStatus);
}
postProcessLocalNew();
finalize();
Expand Down
2 changes: 1 addition & 1 deletion src/libsync/encryptfolderjob.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ void EncryptFolderJob::slotEncryptionFlagSuccess(const QByteArray &fileId)
qCWarning(lcEncryptFolderJob) << "No valid record found in local DB for fileId" << fileId;
}

rec._isE2eEncrypted = SyncJournalFileRecord::EncryptionStatus::EncryptedMigratedV1_2;
rec._e2eEncryptionStatus = 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();
Expand Down
2 changes: 1 addition & 1 deletion src/libsync/owncloudpropagator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -652,7 +652,7 @@ void OwncloudPropagator::startDirectoryPropagation(const SyncFileItemPtr &item,
_anotherSyncNeeded = true;
} else if (item->_isEncryptedMetadataNeedUpdate) {
SyncJournalFileRecord record;
if (_journal->getFileRecord(item->_file, &record) && record._isE2eEncrypted == SyncJournalFileRecord::EncryptionStatus::EncryptedMigratedV1_2) {
if (_journal->getFileRecord(item->_file, &record) && record._e2eEncryptionStatus == SyncJournalFileRecord::EncryptionStatus::EncryptedMigratedV1_2) {
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
2 changes: 1 addition & 1 deletion src/libsync/propagatedownloadencrypted.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ void PropagateDownloadEncrypted::checkFolderEncryptedMetadata(const QJsonDocumen
<< _item->_instruction << _item->_file << _item->_encryptedFileName;
const QString filename = _info.fileName();
const FolderMetadata metadata(_propagator->account(),
_item->_isEncrypted == SyncFileItem::EncryptionStatus::EncryptedMigratedV1_2 ? FolderMetadata::RequiredMetadataVersion::Version1_2 : FolderMetadata::RequiredMetadataVersion::Version1,
_item->_e2eEncryptionStatus == SyncFileItem::EncryptionStatus::EncryptedMigratedV1_2 ? FolderMetadata::RequiredMetadataVersion::Version1_2 : FolderMetadata::RequiredMetadataVersion::Version1,
json.toJson(QJsonDocument::Compact));
if (metadata.isMetadataSetup()) {
const QVector<EncryptedFile> files = metadata.files();
Expand Down
2 changes: 1 addition & 1 deletion src/libsync/propagateremotedeleteencrypted.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ void PropagateRemoteDeleteEncrypted::slotFolderEncryptedMetadataReceived(const Q
}

FolderMetadata metadata(_propagator->account(),
_item->_isEncrypted == SyncFileItem::EncryptionStatus::EncryptedMigratedV1_2 ? FolderMetadata::RequiredMetadataVersion::Version1_2 : FolderMetadata::RequiredMetadataVersion::Version1,
_item->_e2eEncryptionStatus == SyncFileItem::EncryptionStatus::EncryptedMigratedV1_2 ? FolderMetadata::RequiredMetadataVersion::Version1_2 : FolderMetadata::RequiredMetadataVersion::Version1,
json.toJson(QJsonDocument::Compact), statusCode);

if (!metadata.isMetadataSetup()) {
Expand Down
2 changes: 1 addition & 1 deletion src/libsync/propagateremotedeleteencryptedrootfolder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ void PropagateRemoteDeleteEncryptedRootFolder::slotFolderEncryptedMetadataReceiv
}

FolderMetadata metadata(_propagator->account(),
_item->_isEncrypted == SyncFileItem::EncryptionStatus::EncryptedMigratedV1_2 ? FolderMetadata::RequiredMetadataVersion::Version1_2 : FolderMetadata::RequiredMetadataVersion::Version1,
_item->_e2eEncryptionStatus == SyncFileItem::EncryptionStatus::EncryptedMigratedV1_2 ? FolderMetadata::RequiredMetadataVersion::Version1_2 : FolderMetadata::RequiredMetadataVersion::Version1,
json.toJson(QJsonDocument::Compact), statusCode);

if (!metadata.isMetadataSetup()) {
Expand Down
2 changes: 1 addition & 1 deletion src/libsync/propagateremotemkdir.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ void PropagateRemoteMkdir::slotEncryptFolderFinished()
{
qCDebug(lcPropagateRemoteMkdir) << "Success making the new folder encrypted";
propagator()->_activeJobList.removeOne(this);
_item->_isEncrypted = SyncFileItem::EncryptionStatus::EncryptedMigratedV1_2;
_item->_e2eEncryptionStatus = SyncFileItem::EncryptionStatus::EncryptedMigratedV1_2;
success();
}

Expand Down
4 changes: 2 additions & 2 deletions src/libsync/propagateuploadencrypted.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ void PropagateUploadEncrypted::slotFolderEncryptedMetadataReceived(const QJsonDo

// Encrypt File!
_metadata.reset(new FolderMetadata(_propagator->account(),
_item->_isEncrypted == SyncFileItem::EncryptionStatus::EncryptedMigratedV1_2 ? FolderMetadata::RequiredMetadataVersion::Version1_2 : FolderMetadata::RequiredMetadataVersion::Version1,
_item->_e2eEncryptionStatus == SyncFileItem::EncryptionStatus::EncryptedMigratedV1_2 ? FolderMetadata::RequiredMetadataVersion::Version1_2 : FolderMetadata::RequiredMetadataVersion::Version1,
json.toJson(QJsonDocument::Compact), statusCode));

if (!_metadata->isMetadataSetup()) {
Expand Down Expand Up @@ -171,7 +171,7 @@ void PropagateUploadEncrypted::slotFolderEncryptedMetadataReceived(const QJsonDo
encryptedFile.initializationVector = EncryptionHelper::generateRandom(16);

_item->_encryptedFileName = _remoteParentPath + QLatin1Char('/') + encryptedFile.encryptedFilename;
_item->_isEncrypted = SyncFileItem::EncryptionStatus::EncryptedMigratedV1_2;
_item->_e2eEncryptionStatus = SyncFileItem::EncryptionStatus::EncryptedMigratedV1_2;

qCDebug(lcPropagateUploadEncrypted) << "Creating the encrypted file.";

Expand Down
53 changes: 50 additions & 3 deletions src/libsync/syncfileitem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,53 @@ namespace OCC {

Q_LOGGING_CATEGORY(lcFileItem, "nextcloud.sync.fileitem", QtInfoMsg)

namespace EncryptionStatusEnums {

ItemEncryptionStatus fromDbEncryptionStatus(JournalDbEncryptionStatus encryptionStatus)
{
auto result = ItemEncryptionStatus::NotEncrypted;

switch (encryptionStatus)
{
case JournalDbEncryptionStatus::Encrypted:
result = ItemEncryptionStatus::Encrypted;
break;
case JournalDbEncryptionStatus::EncryptedMigratedV1_2:
result = ItemEncryptionStatus::EncryptedMigratedV1_2;
break;
case JournalDbEncryptionStatus::EncryptedMigratedV1_2Invalid:
result = ItemEncryptionStatus::Encrypted;
break;
case JournalDbEncryptionStatus::NotEncrypted:
result = ItemEncryptionStatus::NotEncrypted;
break;
}

return result;
}

JournalDbEncryptionStatus toDbEncryptionStatus(ItemEncryptionStatus encryptionStatus)
{
auto result = JournalDbEncryptionStatus::NotEncrypted;

switch (encryptionStatus)
{
case ItemEncryptionStatus::Encrypted:
result = JournalDbEncryptionStatus::Encrypted;
break;
case ItemEncryptionStatus::EncryptedMigratedV1_2:
result = JournalDbEncryptionStatus::EncryptedMigratedV1_2;
break;
case ItemEncryptionStatus::NotEncrypted:
result = JournalDbEncryptionStatus::NotEncrypted;
break;
}

return result;
}

}

SyncJournalFileRecord SyncFileItem::toSyncJournalFileRecordWithInode(const QString &localFileName) const
{
SyncJournalFileRecord rec;
Expand All @@ -49,7 +96,7 @@ SyncJournalFileRecord SyncFileItem::toSyncJournalFileRecordWithInode(const QStri
rec._serverHasIgnoredFiles = _serverHasIgnoredFiles;
rec._checksumHeader = _checksumHeader;
rec._e2eMangledName = _encryptedFileName.toUtf8();
rec._isE2eEncrypted = isEncrypted() ? SyncJournalFileRecord::EncryptionStatus::EncryptedMigratedV1_2 : SyncJournalFileRecord::EncryptionStatus::NotEncrypted;
rec._e2eEncryptionStatus = EncryptionStatusEnums::toDbEncryptionStatus(_e2eEncryptionStatus);
rec._lockstate._locked = _locked == LockStatus::LockedItem;
rec._lockstate._lockOwnerDisplayName = _lockOwnerDisplayName;
rec._lockstate._lockOwnerId = _lockOwnerId;
Expand Down Expand Up @@ -86,7 +133,7 @@ SyncFileItemPtr SyncFileItem::fromSyncJournalFileRecord(const SyncJournalFileRec
item->_serverHasIgnoredFiles = rec._serverHasIgnoredFiles;
item->_checksumHeader = rec._checksumHeader;
item->_encryptedFileName = rec.e2eMangledName();
item->_isEncrypted = static_cast<SyncFileItem::EncryptionStatus>(rec._isE2eEncrypted);
item->_e2eEncryptionStatus = EncryptionStatusEnums::fromDbEncryptionStatus(rec._e2eEncryptionStatus);
item->_locked = rec._lockstate._locked ? LockStatus::LockedItem : LockStatus::UnlockedItem;
item->_lockOwnerDisplayName = rec._lockstate._lockOwnerDisplayName;
item->_lockOwnerId = rec._lockstate._lockOwnerId;
Expand Down Expand Up @@ -123,7 +170,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") ? SyncFileItem::EncryptionStatus::EncryptedMigratedV1_2 : SyncFileItem::EncryptionStatus::NotEncrypted);
item->_e2eEncryptionStatus = (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"));
Expand Down
11 changes: 3 additions & 8 deletions src/libsync/syncfileitem.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,7 @@ class OWNCLOUDSYNC_EXPORT SyncFileItem
};
Q_ENUM(Direction)

enum class EncryptionStatus : int {
NotEncrypted = 0,
Encrypted = 1,
EncryptedMigratedV1_2 = 2,
};
Q_ENUM(EncryptionStatus)
using EncryptionStatus = EncryptionStatusEnums::ItemEncryptionStatus;

// Note: the order of these statuses is used for ordering in the SortedActivityListModel
enum Status { // stored in 4 bits
Expand Down Expand Up @@ -234,7 +229,7 @@ class OWNCLOUDSYNC_EXPORT SyncFileItem
&& !(_instruction == CSYNC_INSTRUCTION_CONFLICT && _status == SyncFileItem::Success);
}

[[nodiscard]] bool isEncrypted() const { return _isEncrypted != SyncFileItem::EncryptionStatus::NotEncrypted; }
[[nodiscard]] bool isEncrypted() const { return _e2eEncryptionStatus != EncryptionStatus::NotEncrypted; }

// Variables useful for everybody

Expand Down Expand Up @@ -281,7 +276,7 @@ class OWNCLOUDSYNC_EXPORT SyncFileItem
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
EncryptionStatus _isEncrypted = EncryptionStatus::NotEncrypted; // The file is E2EE or the content of the directory should be E2EE
EncryptionStatus _e2eEncryptionStatus = 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
Expand Down
2 changes: 1 addition & 1 deletion test/testfolderman.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 = SyncJournalFileRecord::EncryptionStatus::EncryptedMigratedV1_2;
rec._e2eEncryptionStatus = SyncJournalFileRecord::EncryptionStatus::EncryptedMigratedV1_2;
rec._path = QStringLiteral("encrypted").toUtf8();
rec._type = CSyncEnums::ItemTypeDirectory;
QVERIFY(folder->journalDb()->setFileRecord(rec));
Expand Down

0 comments on commit 985f50a

Please sign in to comment.