mirror of
https://github.com/nextcloud/desktop.git
synced 2025-10-26 11:17:43 +00:00
179 lines
7.5 KiB
C++
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);
|
|
}
|
|
|
|
}
|