From 969612df253451e4e16456665982314edd444801 Mon Sep 17 00:00:00 2001 From: alex-z Date: Fri, 12 Jan 2024 18:41:13 +0100 Subject: [PATCH] Refactoring, code-cleaning, etc. Signed-off-by: alex-z --- src/libsync/encryptedfoldermetadatahandler.h | 1 + src/libsync/foldermetadata.cpp | 17 ++----- src/libsync/foldermetadata.h | 48 ++++++++++++------- .../updatee2eefolderusersmetadatajob.cpp | 2 +- test/testclientsideencryptionv2.cpp | 6 ++- test/testsecurefiledrop.cpp | 2 +- 6 files changed, 43 insertions(+), 33 deletions(-) diff --git a/src/libsync/encryptedfoldermetadatahandler.h b/src/libsync/encryptedfoldermetadatahandler.h index b3c06bffd9c36..d9875a11b8912 100644 --- a/src/libsync/encryptedfoldermetadatahandler.h +++ b/src/libsync/encryptedfoldermetadatahandler.h @@ -25,6 +25,7 @@ namespace OCC { class FolderMetadata; class SyncJournalDb; +// all metadata operations with server must be performed via this class class OWNCLOUDSYNC_EXPORT EncryptedFolderMetadataHandler : public QObject { Q_OBJECT diff --git a/src/libsync/foldermetadata.cpp b/src/libsync/foldermetadata.cpp index 4074793601593..26eb96a732453 100644 --- a/src/libsync/foldermetadata.cpp +++ b/src/libsync/foldermetadata.cpp @@ -535,11 +535,6 @@ const QSet& FolderMetadata::keyChecksums() const return _keyChecksums; } -const QSet& FolderMetadata::keyChecksumsRemoved() const -{ - return _keyChecksumsRemoved; -} - void FolderMetadata::initEmptyMetadata() { if (_account->capabilities().clientSideEncryptionVersion() < 2.0) { @@ -547,7 +542,11 @@ void FolderMetadata::initEmptyMetadata() } qCDebug(lcCseMetadata()) << "Setting up empty metadata v2"; if (_isRootEncryptedFolder) { - addUser(_account->davUser(), _account->e2e()->_certificate); + if (!addUser(_account->davUser(), _account->e2e()->_certificate)) { + qCDebug(lcCseMetadata) << "Empty metadata setup failed. Could not add first user."; + _account->reportClientStatus(OCC::ClientStatusReportingStatus::E2EeError_GeneralError); + return; + } _metadataKeyForDecryption = _metadataKeyForEncryption; } _isMetadataValid = true; @@ -1109,12 +1108,6 @@ void FolderMetadata::createNewMetadataKeyForEncryption() if (!_isRootEncryptedFolder) { return; } - if (!metadataKeyForEncryption().isEmpty()) { - const auto checksumToRemove = calcSha256(metadataKeyForEncryption()); - // TODO: since we are not supposed to remove checksums, we might as well get rid of _keyChecksumsRemoved - _keyChecksumsRemoved.insert(checksumToRemove); - //_keyChecksums.remove(checksumToRemove); - } _metadataKeyForEncryption = EncryptionHelper::generateRandom(metadataKeySize); if (!metadataKeyForEncryption().isEmpty()) { _keyChecksums.insert(calcSha256(metadataKeyForEncryption())); diff --git a/src/libsync/foldermetadata.h b/src/libsync/foldermetadata.h index 2b2626d71fad0..80f276c68c457 100644 --- a/src/libsync/foldermetadata.h +++ b/src/libsync/foldermetadata.h @@ -1,6 +1,6 @@ #pragma once /* - * Copyright (C) 2023 by Oleksandr Zolotov + * Copyright (C) 2024 by Oleksandr Zolotov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -32,11 +32,13 @@ class TestClientSideEncryptionV2; class TestSecureFileDrop; namespace OCC { + // Handles parsing and altering the metadata, encryption and decryption. Setup of the instance is always asynchronouse and emits void setupComplete() class OWNCLOUDSYNC_EXPORT FolderMetadata : public QObject { friend class TestClientSideEncryptionV2; friend class TestSecureFileDrop; Q_OBJECT + // represents a user that has access to a folder for which metadata instance is created struct FolderUser { QString userId; @@ -52,7 +54,7 @@ class OWNCLOUDSYNC_EXPORT FolderMetadata : public QObject Version2_0, }; - // represents a user that has access to a specific filedrop entry + // represents a user that has access to a specific filedrop entry of the current folder struct FileDropEntryUser { QString userId; QByteArray decryptedFiledropKey; @@ -113,15 +115,16 @@ class OWNCLOUDSYNC_EXPORT FolderMetadata : public QObject [[nodiscard]] bool moveFromFileDropToFiles(); - bool addUser(const QString &userId, const QSslCertificate &certificate); //adds a user to have access to this folder (always generates new metadata key) - bool removeUser(const QString &userId); // removes a user from this folder and removes and generates a new metadata key + // adds a user to have access to this folder (always generates new metadata key) + [[nodiscard]] bool addUser(const QString &userId, const QSslCertificate &certificate); + // removes a user from this folder and removes and generates a new metadata key + [[nodiscard]] bool removeUser(const QString &userId); [[nodiscard]] const QByteArray metadataKeyForEncryption() const; [[nodiscard]] const QByteArray metadataKeyForDecryption() const; [[nodiscard]] const QSet &keyChecksums() const; - [[nodiscard]] const QSet &keyChecksumsRemoved() const; - QByteArray encryptedMetadata(); + [[nodiscard]] QByteArray encryptedMetadata(); [[nodiscard]] EncryptionStatusEnums::ItemEncryptionStatus existingMetadataEncryptionStatus() const; [[nodiscard]] EncryptionStatusEnums::ItemEncryptionStatus encryptedMetadataEncryptionStatus() const; @@ -135,8 +138,13 @@ class OWNCLOUDSYNC_EXPORT FolderMetadata : public QObject [[nodiscard]] QByteArray initialMetadata() const; +public slots: + void addEncryptedFile(const EncryptedFile &f); + void removeEncryptedFile(const EncryptedFile &f); + void removeAllEncryptedFiles(); + private: - QByteArray encryptedMetadataLegacy(); + [[nodiscard]] QByteArray encryptedMetadataLegacy(); [[nodiscard]] bool verifyMetadataKey(const QByteArray &metadataKey) const; @@ -165,11 +173,6 @@ class OWNCLOUDSYNC_EXPORT FolderMetadata : public QObject static QByteArray prepareMetadataForSignature(const QJsonDocument &fullMetadata); -public slots: - void addEncryptedFile(const EncryptedFile &f); - void removeEncryptedFile(const EncryptedFile &f); - void removeAllEncryptedFiles(); - private slots: void initMetadata(); void initEmptyMetadata(); @@ -196,34 +199,43 @@ private slots: QByteArray _initialMetadata; bool _isRootEncryptedFolder = false; + // always contains the last generated metadata key (non-encrypted and non-base64) QByteArray _metadataKeyForEncryption; - QByteArray _metadataKeyForDecryption; // used for storing initial metadataKey to use for decryption, especially in nested folders when changing the metadataKey and re-encrypting nested dirs - QSet _keyChecksums; - QSet _keyChecksumsRemoved; + // used for storing initial metadataKey to use for decryption, especially in nested folders when changing the metadataKey and re-encrypting nested dirs + QByteArray _metadataKeyForDecryption; QByteArray _metadataNonce; + // metadatakey checksums for validation during setting up from existing metadata + QSet _keyChecksums; + // filedrop part non-parsed, for upload in case parsing can not be done (due to not having access for the current user, etc.) QJsonObject _fileDrop; // used by unit tests, must get assigned simultaneously with _fileDrop and never erased QJsonObject _fileDropFromServer; - QMap _metadataKeys; //legacy, remove after migration is done + // legacy, remove after migration is done + QMap _metadataKeys; + // users that have access to current folder's "ciphertext", except "filedrop" part QHash _folderUsers; + // must increment on each metadata upload quint64 _counter = 0; MetadataVersion _existingMetadataVersion = MetadataVersion::VersionUndefined; MetadataVersion _encryptedMetadataVersion = MetadataVersion::VersionUndefined; + // generated each time QByteArray encryptedMetadata() is called, and will later be used for validation if uploaded QByteArray _metadataSignature; - + // signature from server-side metadata QByteArray _initialSignature; + // both files and folders info QVector _files; - // for parsed filedrop entries + // parsed filedrop entries ready for move QVector _fileDropEntries; + // sets to "true" on successful parse bool _isMetadataValid = false; QScopedPointer _encryptedFolderMetadataHandler; diff --git a/src/libsync/updatee2eefolderusersmetadatajob.cpp b/src/libsync/updatee2eefolderusersmetadatajob.cpp index f08e6fbf75e31..b271a9e5a574c 100644 --- a/src/libsync/updatee2eefolderusersmetadatajob.cpp +++ b/src/libsync/updatee2eefolderusersmetadatajob.cpp @@ -201,7 +201,7 @@ void UpdateE2eeFolderUsersMetadataJob::scheduleSubJobs() const auto subJob = new UpdateE2eeFolderUsersMetadataJob(_account, _journalDb, _syncFolderRemotePath, UpdateE2eeFolderUsersMetadataJob::ReEncrypt, QString::fromUtf8(record._e2eMangledName)); subJob->setMetadataKeyForEncryption(folderMetadata->metadataKeyForEncryption()); subJob->setMetadataKeyForDecryption(folderMetadata->metadataKeyForDecryption()); - subJob->setKeyChecksums(folderMetadata->keyChecksums() + folderMetadata->keyChecksumsRemoved()); + subJob->setKeyChecksums(folderMetadata->keyChecksums()); subJob->setParent(this); subJob->setFolderToken(_encryptedFolderMetadataHandler->folderToken()); _subJobs.insert(subJob); diff --git a/test/testclientsideencryptionv2.cpp b/test/testclientsideencryptionv2.cpp index aa0172e16df0c..81e5addc5bef4 100644 --- a/test/testclientsideencryptionv2.cpp +++ b/test/testclientsideencryptionv2.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) by Oleksandr Zolotov + * Copyright (C) 2024 by Oleksandr Zolotov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -214,6 +214,10 @@ private slots: QVERIFY(metadata->addUser(_secondAccount->davUser(), _secondAccount->e2e()->_certificate)); + QVERIFY(metadata->removeUser(_secondAccount->davUser())); + + QVERIFY(metadata->addUser(_secondAccount->davUser(), _secondAccount->e2e()->_certificate)); + const auto encryptedMetadata = metadata->encryptedMetadata(); QVERIFY(!encryptedMetadata.isEmpty()); diff --git a/test/testsecurefiledrop.cpp b/test/testsecurefiledrop.cpp index fbf2c47d50383..69f4a13d13b87 100644 --- a/test/testsecurefiledrop.cpp +++ b/test/testsecurefiledrop.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) by Oleksandr Zolotov + * Copyright (C) 2024 by Oleksandr Zolotov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by