Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/common/remoteinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ struct RemoteInfo
bool _isE2eEncrypted = false;
bool isFileDropDetected = false;
QString e2eMangledName;
QByteArray _e2eFileEncryptionKey;
QByteArray _initializationVector;
QByteArray _authenticationTag;
bool sharedByMe = false;

[[nodiscard]] bool isValid() const { return !name.isNull(); }
Expand Down
22 changes: 18 additions & 4 deletions src/common/syncjournaldb.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ Q_LOGGING_CATEGORY(lcDb, "nextcloud.sync.database", QtInfoMsg)
"SELECT path, inode, modtime, type, md5, fileid, remotePerm, filesize," \
" ignoredChildrenRemote, contentchecksumtype.name || ':' || contentChecksum, e2eMangledName, isE2eEncrypted, e2eCertificateFingerprint, " \
" lock, lockOwnerDisplayName, lockOwnerId, lockType, lockOwnerEditor, lockTime, lockTimeout, lockToken, isShared, lastShareStateFetchedTimestmap, " \
" sharedByMe, isLivePhoto, livePhotoFile, quotaBytesUsed, quotaBytesAvailable" \
" sharedByMe, isLivePhoto, livePhotoFile, quotaBytesUsed, quotaBytesAvailable, e2eFileEncryptionKey, authenticationTag, initializationVector" \
" FROM metadata" \
" LEFT JOIN checksumtype as contentchecksumtype ON metadata.contentChecksumTypeId == contentchecksumtype.id"

Expand All @@ -66,6 +66,9 @@ static void fillFileRecordFromGetQuery(SyncJournalFileRecord &rec, SqlQuery &que
rec._checksumHeader = query.baValue(9);
rec._e2eMangledName = query.baValue(10);
rec._e2eEncryptionStatus = static_cast<SyncJournalFileRecord::EncryptionStatus>(query.intValue(11));
rec._e2eFileEncryptionKey = query.baValue(28);
rec._authenticationTag = query.baValue(29);
rec._initializationVector = query.baValue(30);
rec._lockstate._locked = query.intValue(13) > 0;
rec._lockstate._lockOwnerDisplayName = query.stringValue(14);
rec._lockstate._lockOwnerId = query.stringValue(15);
Expand Down Expand Up @@ -928,6 +931,10 @@ bool SyncJournalDb::updateMetadataTableStructure()
addColumn(quotaBytesAvailable, bigInt, false, defaultCommand);
}

addColumn(u"e2eFileEncryptionKey"_s, u"TEXT"_s);
addColumn(u"authenticationTag"_s, u"TEXT"_s);
addColumn(u"initializationVector"_s, u"TEXT"_s);

return re;
}

Expand Down Expand Up @@ -1089,9 +1096,13 @@ Result<void, QString> SyncJournalDb::setFileRecord(const SyncJournalFileRecord &

const auto query = _queryManager.get(PreparedSqlQueryManager::SetFileRecordQuery, QByteArrayLiteral("INSERT OR REPLACE INTO metadata "
"(phash, pathlen, path, inode, uid, gid, mode, modtime, type, md5, fileid, remotePerm, filesize, ignoredChildrenRemote, "
"contentChecksum, contentChecksumTypeId, e2eMangledName, isE2eEncrypted, e2eCertificateFingerprint, lock, lockType, lockOwnerDisplayName, lockOwnerId, "
"lockOwnerEditor, lockTime, lockTimeout, lockToken, isShared, lastShareStateFetchedTimestmap, sharedByMe, isLivePhoto, livePhotoFile, quotaBytesUsed, quotaBytesAvailable) "
"VALUES (?1 , ?2, ?3 , ?4 , ?5 , ?6 , ?7, ?8 , ?9 , ?10, ?11, ?12, ?13, ?14, ?15, ?16, ?17, ?18, ?19, ?20, ?21, ?22, ?23, ?24, ?25, ?26, ?27, ?28, ?29, ?30, ?31, ?32, ?33, ?34);"),
"contentChecksum, contentChecksumTypeId, e2eMangledName, isE2eEncrypted, e2eCertificateFingerprint, "
"lock, lockType, lockOwnerDisplayName, lockOwnerId, "
"lockOwnerEditor, lockTime, lockTimeout, lockToken, isShared, lastShareStateFetchedTimestmap, "
"sharedByMe, isLivePhoto, livePhotoFile, quotaBytesUsed, quotaBytesAvailable, "
"e2eFileEncryptionKey, authenticationTag, initializationVector) "
"VALUES (?1 , ?2, ?3 , ?4 , ?5 , ?6 , ?7, ?8 , ?9 , ?10, ?11, ?12, ?13, ?14, ?15, ?16, ?17, "
"?18, ?19, ?20, ?21, ?22, ?23, ?24, ?25, ?26, ?27, ?28, ?29, ?30, ?31, ?32, ?33, ?34, ?35, ?36, ?37);"),
_db);
if (!query) {
qCWarning(lcDb) << "database error:" << query->error();
Expand All @@ -1117,6 +1128,9 @@ Result<void, QString> SyncJournalDb::setFileRecord(const SyncJournalFileRecord &
query->bindValue(17, record._e2eMangledName);
query->bindValue(18, static_cast<int>(record._e2eEncryptionStatus));
query->bindValue(19, {});
query->bindValue(35, record._e2eFileEncryptionKey);
query->bindValue(36, record._authenticationTag);
query->bindValue(37, record._initializationVector);
query->bindValue(20, record._lockstate._locked ? 1 : 0);
query->bindValue(21, record._lockstate._lockOwnerType);
query->bindValue(22, record._lockstate._lockOwnerDisplayName);
Expand Down
3 changes: 3 additions & 0 deletions src/common/syncjournalfilerecord.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ class OCSYNC_EXPORT SyncJournalFileRecord
QByteArray _checksumHeader;
QByteArray _e2eMangledName;
EncryptionStatus _e2eEncryptionStatus = EncryptionStatus::NotEncrypted;
QByteArray _e2eFileEncryptionKey;
QByteArray _initializationVector;
QByteArray _authenticationTag;
SyncJournalFileLockInfo _lockstate;
bool _isShared = false;
qint64 _lastShareStateFetchedTimestamp = 0;
Expand Down
51 changes: 51 additions & 0 deletions src/gui/accountsettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "tooltipupdater.h"
#include "filesystem.h"
#include "encryptfolderjob.h"
#include "repairfolderencryptionmetadatajob.h"
#include "syncresult.h"
#include "ignorelisttablewidget.h"
#include "networksettings.h"
Expand Down Expand Up @@ -455,6 +456,25 @@ void AccountSettings::slotEncryptFolderFinished(int status)
job->deleteLater();
}

void AccountSettings::slotRepairEncryptedFolderFinished(int status)
{
qCInfo(lcAccountSettings) << "Current folder encryption status code:" << status;
auto job = qobject_cast<RepairFolderEncryptionMetadataJob*>(sender());
Q_ASSERT(job);
if (!job->errorString().isEmpty()) {
QMessageBox::warning(nullptr, tr("Repair of encryption failed"), job->errorString());
}

const auto folder = job->property(propertyFolder).value<Folder *>();
Q_ASSERT(folder);
const auto path = job->property(propertyPath).toString();
const auto index = _model->indexForPath(folder, path);
Q_ASSERT(index.isValid());
_model->resetAndFetch(index.parent());

job->deleteLater();
}

QString AccountSettings::selectedFolderAlias() const
{
const auto selected = _ui->_folderList->selectionModel()->currentIndex();
Expand Down Expand Up @@ -590,6 +610,33 @@ void AccountSettings::slotMarkSubfolderEncrypted(FolderStatusModel::SubFolderInf
showEnableE2eeWarningDialog(encryptFolder);
}

void AccountSettings::slotRepairEncryptedSubfolder(FolderStatusModel::SubFolderInfo *folderInfo)
{
const auto folder = folderInfo->_folder;
Q_ASSERT(folder);

const auto folderAlias = folder->alias();
const auto path = folderInfo->_path;
const auto fileId = folderInfo->_fileId;

if (!folder) {
qCWarning(lcAccountSettings) << "Could not repair encrypted folder because folder" << folderAlias << "does not exist anymore";
QMessageBox::warning(nullptr, tr("Repair of encryption failed"), tr("Could not repair encryption because the folder does not exist anymore"));
return;
}

// Folder info have directory paths in Foo/Bar/ convention...
Q_ASSERT(!path.startsWith('/') && path.endsWith('/'));
// But EncryptFolderJob expects directory path Foo/Bar convention
const auto choppedPath = path.chopped(1);
auto job = new RepairFolderEncryptionMetadataJob(accountsState()->account(), folder->journalDb(), choppedPath, choppedPath, folder->remotePath(), fileId);
job->setParent(this);
job->setProperty(propertyFolder, QVariant::fromValue(folder));
job->setProperty(propertyPath, QVariant::fromValue(path));
connect(job, &RepairFolderEncryptionMetadataJob::finished, this, &AccountSettings::slotRepairEncryptedFolderFinished);
job->start();
}

void AccountSettings::slotEditCurrentIgnoredFiles()
{
const auto folder = FolderMan::instance()->folder(selectedFolderAlias());
Expand Down Expand Up @@ -713,6 +760,10 @@ void AccountSettings::slotSubfolderContextMenuRequested(const QModelIndex& index
// Ignore decrypting for now since it only works with an empty folder
// connect(ac, &QAction::triggered, [this, &info] { slotMarkSubfolderDecrypted(info); });
}
if (isEncrypted && _accountState->account()->e2e()->isInitialized()) {
ac = menu.addAction(tr("Repair encryption"));
connect(ac, &QAction::triggered, [this, info] { slotRepairEncryptedSubfolder(info); });
}
}

ac = menu.addAction(tr("Edit Ignored Files"));
Expand Down
2 changes: 2 additions & 0 deletions src/gui/accountsettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ protected Q_SLOTS:
void slotToggleSignInState();
void refreshSelectiveSyncStatus();
void slotMarkSubfolderEncrypted(OCC::FolderStatusModel::SubFolderInfo *folderInfo);
void slotRepairEncryptedSubfolder(OCC::FolderStatusModel::SubFolderInfo *folderInfo);
void slotSubfolderContextMenuRequested(const QModelIndex& idx, const QPoint& point);
void slotCustomContextMenuRequested(const QPoint &);
void slotFolderListClicked(const QModelIndex &indx);
Expand All @@ -122,6 +123,7 @@ protected Q_SLOTS:
void slotE2eEncryptionGenerateKeys();
void slotE2eEncryptionInitializationFinished(bool isNewMnemonicGenerated);
void slotEncryptFolderFinished(int status);
void slotRepairEncryptedFolderFinished(int status);

void slotSelectiveSyncChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight,
const QVector<int> &roles);
Expand Down
2 changes: 1 addition & 1 deletion src/gui/folder.h
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,7 @@ public Q_SLOTS:
void slotTerminateSync();

// connected to the corresponding signals in the SyncEngine
void slotAboutToRemoveAllFiles(OCC::SyncFileItem::Direction, std::function<void(bool)> callback);
void slotAboutToRemoveAllFiles(OCC::SyncFileItem::Direction, std::function<void(bool)> callback);// clazy:exclude=fully-qualified-moc-types

/**
* Starts a sync operation
Expand Down
2 changes: 1 addition & 1 deletion src/gui/owncloudgui.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ public Q_SLOTS:
* to the folder).
*/
void slotShowShareDialog(const QString &localPath) const;
void slotShowGovernanceLabelsDialog(AccountPtr account,
void slotShowGovernanceLabelsDialog(OCC::AccountPtr account,
const QString &localPath,
const QString &fileId) const;
void slotShowFileActivityDialog(const QString &localPath) const;
Expand Down
2 changes: 1 addition & 1 deletion src/gui/systray.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ public Q_SLOTS:
void createEditFileLocallyLoadingDialog(const QString &fileName);
void destroyEditFileLocallyLoadingDialog();
void createResolveConflictsDialog(const OCC::ActivityList &allConflicts);
void createGovernanceLabelsDialog(AccountPtr account, const QString &fileName, const QString &fileId);
void createGovernanceLabelsDialog(OCC::AccountPtr account, const QString &fileName, const QString &fileId);
void createEncryptionTokenDiscoveryDialog();
void destroyEncryptionTokenDiscoveryDialog();

Expand Down
4 changes: 2 additions & 2 deletions src/gui/tray/usermodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -203,8 +203,8 @@ public Q_SLOTS:
private Q_SLOTS:
void slotPushNotificationsReady();
void slotDisconnectPushNotifications();
void slotReceivedPushFilesChanges(Account *account);
void slotReceivedPushFileIdsChanges(Account *account, const QList<qint64> &fileIds);
void slotReceivedPushFilesChanges(OCC::Account *account);
void slotReceivedPushFileIdsChanges(OCC::Account *account, const QList<qint64> &fileIds);
void slotReceivedPushNotification(OCC::Account *account);
void slotReceivedPushActivity(OCC::Account *account);
void slotCheckExpiredActivities();
Expand Down
2 changes: 2 additions & 0 deletions src/libsync/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ set(libsync_SRCS
clientsideencryptionprimitives.cpp
clientsideencryptiontokenselector.h
clientsideencryptiontokenselector.cpp
repairfolderencryptionmetadatajob.h
repairfolderencryptionmetadatajob.cpp
datetimeprovider.h
datetimeprovider.cpp
rootencryptedfolderinfo.h
Expand Down
2 changes: 2 additions & 0 deletions src/libsync/abstractnetworkjob.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -624,3 +624,5 @@ std::optional<QString> AbstractNetworkJob::hstsErrorStringFromReply(QNetworkRepl
}

} // namespace OCC

#include "moc_abstractnetworkjob.cpp"
8 changes: 4 additions & 4 deletions src/libsync/clientsideencryption.h
Original file line number Diff line number Diff line change
Expand Up @@ -332,10 +332,10 @@ private Q_SLOTS:
void privateKeyFetched(QKeychain::Job *incoming);
void mnemonicKeyFetched(QKeychain::Job *incoming);

void handlePrivateKeyDeleted(const QKeychain::Job* const incoming);
void handleCertificateDeleted(const QKeychain::Job* const incoming);
void handleMnemonicDeleted(const QKeychain::Job* const incoming);
void handlePublicKeyDeleted(const QKeychain::Job* const incoming);
void handlePrivateKeyDeleted(const QKeychain::Job* incoming);
void handleCertificateDeleted(const QKeychain::Job* incoming);
void handleMnemonicDeleted(const QKeychain::Job* incoming);
void handlePublicKeyDeleted(const QKeychain::Job* incoming);
void checkAllSensitiveDataDeleted();

void getPrivateKeyFromServer();
Expand Down
3 changes: 3 additions & 0 deletions src/libsync/discovery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -776,6 +776,9 @@ void ProcessDirectoryJob::processFileAnalyzeRemoteInfo(const SyncFileItemPtr &it
result = serverEntry.e2eMangledName.mid(rootPath.length());
return result;
}();
item->_e2eFileEncryptionKey = serverEntry._e2eFileEncryptionKey;
item->_initializationVector = serverEntry._initializationVector;
item->_authenticationTag = serverEntry._authenticationTag;
item->_locked = serverEntry.locked;
item->_lockOwnerDisplayName = serverEntry.lockOwnerDisplayName;
item->_lockOwnerId = serverEntry.lockOwnerId;
Expand Down
3 changes: 3 additions & 0 deletions src/libsync/discoveryphase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -731,6 +731,9 @@ void DiscoverySingleDirectoryJob::metadataReceived(const QJsonDocument &json, in
result._isE2eEncrypted = true;
result.e2eMangledName = _subPath.mid(1) + u'/' + result.name;
result.name = encryptedFileInfo->originalFilename;
result._e2eFileEncryptionKey = encryptedFileInfo->encryptionKey;
result._initializationVector = encryptedFileInfo->initializationVector;
result._authenticationTag = encryptedFileInfo->authenticationTag;
}
return result;
});
Expand Down
6 changes: 6 additions & 0 deletions src/libsync/encryptedfoldermetadatahandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,12 @@ void EncryptedFolderMetadataHandler::unlockFolder(const UnlockFolderWithResult r
unlockJob->start();
}

void EncryptedFolderMetadataHandler::repairMetadata(const QList<FolderMetadata::DatabaseEncryptedFile> &childItems,
OwncloudPropagator *propagator)
{
_folderMetadata->repair(childItems, propagator);
}

void EncryptedFolderMetadataHandler::startUploadMetadata()
{
qCDebug(lcFetchAndUploadE2eeFolderMetadataJob) << "Metadata created, sending to the server.";
Expand Down
14 changes: 10 additions & 4 deletions src/libsync/encryptedfoldermetadatahandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "account.h"
#include "rootencryptedfolderinfo.h"
#include "common/syncjournaldb.h"
#include "foldermetadata.h"

#include <QHash>
#include <QMutex>
Expand All @@ -19,8 +20,10 @@
#include <QPointer>

namespace OCC {
class FolderMetadata;

class SyncJournalDb;
class OwncloudPropagator;

// all metadata operations with server must be performed via this class
class OWNCLOUDSYNC_EXPORT EncryptedFolderMetadataHandler
: public QObject
Expand All @@ -30,19 +33,20 @@ class OWNCLOUDSYNC_EXPORT EncryptedFolderMetadataHandler
public:
enum class FetchMode {
NonEmptyMetadata = 0,
AllowEmptyMetadata
AllowEmptyMetadata,
AllowBrokenSignature,
};
Q_ENUM(FetchMode);

enum class UploadMode {
DoNotKeepLock = 0,
KeepLock
KeepLock,
};
Q_ENUM(UploadMode);

enum class UnlockFolderWithResult {
Success = 0,
Failure
Failure,
};
Q_ENUM(UnlockFolderWithResult);

Expand All @@ -66,6 +70,8 @@ class OWNCLOUDSYNC_EXPORT EncryptedFolderMetadataHandler
void fetchMetadata(const FetchMode fetchMode = FetchMode::NonEmptyMetadata);
void uploadMetadata(const UploadMode uploadMode = UploadMode::DoNotKeepLock);
void unlockFolder(const UnlockFolderWithResult result = UnlockFolderWithResult::Success);
void repairMetadata(const QList<OCC::FolderMetadata::DatabaseEncryptedFile> &childItems,
OwncloudPropagator *propagator);

private:
void lockFolder();
Expand Down
Loading