nextcloud-desktop/src/libsync/updatee2eefoldermetadatajob.cpp
Matthieu Gallien 2a52ec33b0 add support to use PKCS#11 harware token to store certifice for e2ee
Close #5685

Signed-off-by: Matthieu Gallien <matthieu.gallien@nextcloud.com>
2025-02-07 09:12:29 +01:00

179 lines
7.5 KiB
C++

/*
* Copyright (C) 2023 by Oleksandr Zolotov <alex@nextcloud.com>
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "updatee2eefoldermetadatajob.h"
#include "account.h"
#include "clientsideencryption.h"
#include "foldermetadata.h"
#include <QLoggingCategory>
#include <QNetworkReply>
namespace OCC {
Q_LOGGING_CATEGORY(lcUpdateFileDropMetadataJob, "nextcloud.sync.propagator.updatee2eefoldermetadatajob", QtInfoMsg)
}
namespace OCC {
UpdateE2eeFolderMetadataJob::UpdateE2eeFolderMetadataJob(OwncloudPropagator *propagator, const SyncFileItemPtr &item, const QString &encryptedRemotePath)
: PropagatorJob(propagator),
_item(item),
_encryptedRemotePath(Utility::noLeadingSlashPath(propagator->fullRemotePath(encryptedRemotePath)))
{
Q_ASSERT(propagator->remotePath() == QStringLiteral("/") || _encryptedRemotePath.startsWith(Utility::noLeadingSlashPath(propagator->remotePath())));
}
void UpdateE2eeFolderMetadataJob::start()
{
Q_ASSERT(_item);
qCDebug(lcUpdateFileDropMetadataJob) << "Folder is encrypted, let's fetch metadata.";
SyncJournalFileRecord rec;
if (!propagator()->_journal->getRootE2eFolderRecord(Utility::fullRemotePathToRemoteSyncRootRelative(_encryptedRemotePath, propagator()->remotePath()), &rec) || !rec.isValid()) {
unlockFolder(EncryptedFolderMetadataHandler::UnlockFolderWithResult::Failure);
return;
}
_encryptedFolderMetadataHandler.reset(
new EncryptedFolderMetadataHandler(propagator()->account(), _encryptedRemotePath, propagator()->remotePath() , propagator()->_journal, rec.path()));
connect(_encryptedFolderMetadataHandler.data(), &EncryptedFolderMetadataHandler::fetchFinished,
this, &UpdateE2eeFolderMetadataJob::slotFetchMetadataJobFinished);
_encryptedFolderMetadataHandler->fetchMetadata(EncryptedFolderMetadataHandler::FetchMode::AllowEmptyMetadata);
}
bool UpdateE2eeFolderMetadataJob::scheduleSelfOrChild()
{
if (_state == Finished) {
return false;
}
if (_state == NotYetStarted) {
_state = Running;
start();
}
return true;
}
PropagatorJob::JobParallelism UpdateE2eeFolderMetadataJob::parallelism() const
{
return PropagatorJob::JobParallelism::WaitForFinished;
}
void UpdateE2eeFolderMetadataJob::slotFetchMetadataJobFinished(int httpReturnCode, const QString &message)
{
if (httpReturnCode != 200) {
qCDebug(lcUpdateFileDropMetadataJob()) << "Error Getting the encrypted metadata.";
_item->_status = SyncFileItem::FatalError;
_item->_errorString = message;
emit finished(SyncFileItem::FatalError);
return;
}
SyncJournalFileRecord rec;
if (!propagator()->_journal->getRootE2eFolderRecord(Utility::fullRemotePathToRemoteSyncRootRelative(_encryptedRemotePath, propagator()->remotePath()), &rec)
|| !rec.isValid()) {
unlockFolder(EncryptedFolderMetadataHandler::UnlockFolderWithResult::Failure);
return;
}
const auto folderMetadata = _encryptedFolderMetadataHandler->folderMetadata();
if (!folderMetadata || !folderMetadata->isValid() || (!folderMetadata->moveFromFileDropToFiles() && !folderMetadata->encryptedMetadataNeedUpdate())) {
unlockFolder(EncryptedFolderMetadataHandler::UnlockFolderWithResult::Failure);
return;
}
emit fileDropMetadataParsedAndAdjusted(folderMetadata.data());
_encryptedFolderMetadataHandler->uploadMetadata();
connect(_encryptedFolderMetadataHandler.data(), &EncryptedFolderMetadataHandler::uploadFinished,
this, &UpdateE2eeFolderMetadataJob::slotUpdateMetadataFinished);
}
void UpdateE2eeFolderMetadataJob::slotUpdateMetadataFinished(int httpReturnCode, const QString &message)
{
const auto itemStatus = httpReturnCode != 200 ? SyncFileItem::FatalError : SyncFileItem::Success;
if (httpReturnCode != 200) {
_item->_errorString = message;
qCDebug(lcUpdateFileDropMetadataJob) << "Update metadata error for folder" << _encryptedFolderMetadataHandler->folderId() << "with error" << httpReturnCode << message;
} else {
qCDebug(lcUpdateFileDropMetadataJob) << "Uploading of the metadata success, Encrypting the file";
}
propagator()->_journal->schedulePathForRemoteDiscovery(_item->_file);
propagator()->_anotherSyncNeeded = true;
_item->_status = itemStatus;
emit finished(itemStatus);
}
void UpdateE2eeFolderMetadataJob::unlockFolder(const EncryptedFolderMetadataHandler::UnlockFolderWithResult result)
{
Q_ASSERT(!_encryptedFolderMetadataHandler->isUnlockRunning());
Q_ASSERT(_item);
if (_encryptedFolderMetadataHandler->isUnlockRunning()) {
qCWarning(lcUpdateFileDropMetadataJob) << "Double-call to unlockFolder.";
return;
}
if (result != EncryptedFolderMetadataHandler::UnlockFolderWithResult::Success) {
_item->_errorString = tr("Failed to update folder metadata.");
}
const auto isSuccess = result == EncryptedFolderMetadataHandler::UnlockFolderWithResult::Success;
const auto itemStatus = isSuccess ? SyncFileItem::Success : SyncFileItem::FatalError;
if (!_encryptedFolderMetadataHandler->isFolderLocked()) {
if (isSuccess && _encryptedFolderMetadataHandler->folderMetadata()) {
_item->_e2eEncryptionStatus = _encryptedFolderMetadataHandler->folderMetadata()->encryptedMetadataEncryptionStatus();
if (_item->isEncrypted()) {
_item->_e2eEncryptionServerCapability = EncryptionStatusEnums::fromEndToEndEncryptionApiVersion(propagator()->account()->capabilities().clientSideEncryptionVersion());
}
}
emit finished(itemStatus);
return;
}
qCDebug(lcUpdateFileDropMetadataJob) << "Calling Unlock";
connect(_encryptedFolderMetadataHandler.data(), &EncryptedFolderMetadataHandler::folderUnlocked, _encryptedFolderMetadataHandler.data(), [this](const QByteArray &folderId, int httpStatus) {
if (httpStatus != 200) {
qCWarning(lcUpdateFileDropMetadataJob) << "Unlock Error" << folderId << httpStatus;
propagator()->account()->reportClientStatus(OCC::ClientStatusReportingStatus::E2EeError_GeneralError);
_item->_errorString = tr("Failed to unlock encrypted folder.");
emit finished(SyncFileItem::FatalError);
return;
}
qCDebug(lcUpdateFileDropMetadataJob) << "Successfully Unlocked";
if (!_encryptedFolderMetadataHandler->folderMetadata()
|| !_encryptedFolderMetadataHandler->folderMetadata()->isValid()) {
qCWarning(lcUpdateFileDropMetadataJob) << "Failed to finalize item. Invalid metadata.";
_item->_errorString = tr("Failed to finalize item.");
emit finished(SyncFileItem::FatalError);
return;
}
_item->_e2eEncryptionStatus = _encryptedFolderMetadataHandler->folderMetadata()->encryptedMetadataEncryptionStatus();
_item->_e2eEncryptionStatusRemote = _encryptedFolderMetadataHandler->folderMetadata()->encryptedMetadataEncryptionStatus();
emit finished(SyncFileItem::Success);
});
_encryptedFolderMetadataHandler->unlockFolder(result);
}
}