mirror of
https://github.com/nextcloud/desktop.git
synced 2025-10-26 11:17:43 +00:00
190 lines
7.8 KiB
C++
190 lines
7.8 KiB
C++
#include "propagateuploadencrypted.h"
|
|
#include "clientsideencryptionjobs.h"
|
|
#include "networkjobs.h"
|
|
#include "clientsideencryption.h"
|
|
#include "foldermetadata.h"
|
|
#include "encryptedfoldermetadatahandler.h"
|
|
#include "filesystem.h"
|
|
#include "account.h"
|
|
#include <QFileInfo>
|
|
#include <QDir>
|
|
#include <QUrl>
|
|
#include <QFile>
|
|
#include <QTemporaryFile>
|
|
#include <QLoggingCategory>
|
|
#include <QMimeDatabase>
|
|
|
|
namespace OCC {
|
|
|
|
Q_LOGGING_CATEGORY(lcPropagateUploadEncrypted, "nextcloud.sync.propagator.upload.encrypted", QtInfoMsg)
|
|
|
|
PropagateUploadEncrypted::PropagateUploadEncrypted(OwncloudPropagator *propagator, const QString &remoteParentPath, SyncFileItemPtr item, QObject *parent)
|
|
: QObject(parent)
|
|
, _propagator(propagator)
|
|
, _remoteParentPath(Utility::noLeadingSlashPath(remoteParentPath))
|
|
, _item(item)
|
|
{
|
|
const auto rootPath = Utility::trailingSlashPath(Utility::noLeadingSlashPath(_propagator->remotePath()));
|
|
_remoteParentAbsolutePath = Utility::noTrailingSlashPath(rootPath + _remoteParentPath);
|
|
}
|
|
|
|
void PropagateUploadEncrypted::start()
|
|
{
|
|
/* If the file is in a encrypted folder, which we know, we wouldn't be here otherwise,
|
|
* we need to do the long road:
|
|
* find the ID of the folder.
|
|
* lock the folder using it's id.
|
|
* download the metadata
|
|
* update the metadata
|
|
* upload the file
|
|
* upload the metadata
|
|
* unlock the folder.
|
|
*/
|
|
// Encrypt File!
|
|
SyncJournalFileRecord rec;
|
|
if (!_propagator->_journal->getRootE2eFolderRecord(Utility::fullRemotePathToRemoteSyncRootRelative(_remoteParentAbsolutePath, _propagator->remotePath()),
|
|
&rec)
|
|
|| !rec.isValid()) {
|
|
emit error();
|
|
return;
|
|
}
|
|
_encryptedFolderMetadataHandler.reset(new EncryptedFolderMetadataHandler(_propagator->account(),
|
|
_remoteParentAbsolutePath,
|
|
_propagator->remotePath(),
|
|
_propagator->_journal,
|
|
rec.path()));
|
|
|
|
connect(_encryptedFolderMetadataHandler.data(), &EncryptedFolderMetadataHandler::fetchFinished,
|
|
this, &PropagateUploadEncrypted::slotFetchMetadataJobFinished);
|
|
_encryptedFolderMetadataHandler->fetchMetadata(EncryptedFolderMetadataHandler::FetchMode::AllowEmptyMetadata);
|
|
}
|
|
|
|
void PropagateUploadEncrypted::unlockFolder()
|
|
{
|
|
connect(_encryptedFolderMetadataHandler.data(), &EncryptedFolderMetadataHandler::folderUnlocked, this, &PropagateUploadEncrypted::folderUnlocked);
|
|
_encryptedFolderMetadataHandler->unlockFolder();
|
|
}
|
|
|
|
bool PropagateUploadEncrypted::isUnlockRunning() const
|
|
{
|
|
return _encryptedFolderMetadataHandler->isUnlockRunning();
|
|
}
|
|
|
|
bool PropagateUploadEncrypted::isFolderLocked() const
|
|
{
|
|
return _encryptedFolderMetadataHandler->isFolderLocked();
|
|
}
|
|
|
|
const QByteArray PropagateUploadEncrypted::folderToken() const
|
|
{
|
|
return _encryptedFolderMetadataHandler ? _encryptedFolderMetadataHandler->folderToken() : QByteArray{};
|
|
}
|
|
|
|
void PropagateUploadEncrypted::slotFetchMetadataJobFinished(int statusCode, const QString &message)
|
|
{
|
|
qCDebug(lcPropagateUploadEncrypted) << "Metadata Received, Preparing it for the new file." << message;
|
|
|
|
if (statusCode != 200) {
|
|
emit error();
|
|
return;
|
|
}
|
|
|
|
if (!_encryptedFolderMetadataHandler->folderMetadata() || !_encryptedFolderMetadataHandler->folderMetadata()->isValid()) {
|
|
qCDebug(lcPropagateUploadEncrypted()) << "There was an error encrypting the file, aborting upload. Invalid metadata.";
|
|
emit error();
|
|
return;
|
|
}
|
|
|
|
|
|
const auto metadata = _encryptedFolderMetadataHandler->folderMetadata();
|
|
|
|
QFileInfo info(_propagator->fullLocalPath(_item->_file));
|
|
const QString fileName = info.fileName();
|
|
|
|
// Find existing metadata for this file
|
|
bool found = false;
|
|
FolderMetadata::EncryptedFile encryptedFile;
|
|
const QVector<FolderMetadata::EncryptedFile> files = metadata->files();
|
|
|
|
for (const FolderMetadata::EncryptedFile &file : files) {
|
|
if (file.originalFilename == fileName) {
|
|
encryptedFile = file;
|
|
found = true;
|
|
}
|
|
}
|
|
|
|
// New encrypted file so set it all up!
|
|
if (!found) {
|
|
encryptedFile.encryptionKey = EncryptionHelper::generateRandom(16);
|
|
encryptedFile.encryptedFilename = EncryptionHelper::generateRandomFilename();
|
|
encryptedFile.originalFilename = fileName;
|
|
|
|
QMimeDatabase mdb;
|
|
encryptedFile.mimetype = mdb.mimeTypeForFile(info).name().toLocal8Bit();
|
|
|
|
// Other clients expect "httpd/unix-directory" instead of "inode/directory"
|
|
// Doesn't matter much for us since we don't do much about that mimetype anyway
|
|
if (encryptedFile.mimetype == QByteArrayLiteral("inode/directory")) {
|
|
encryptedFile.mimetype = QByteArrayLiteral("httpd/unix-directory");
|
|
}
|
|
}
|
|
|
|
encryptedFile.initializationVector = EncryptionHelper::generateRandom(16);
|
|
|
|
_item->_encryptedFileName = Utility::trailingSlashPath(_remoteParentPath) + encryptedFile.encryptedFilename;
|
|
_item->_e2eEncryptionStatusRemote = metadata->existingMetadataEncryptionStatus();
|
|
_item->_e2eEncryptionServerCapability =
|
|
EncryptionStatusEnums::fromEndToEndEncryptionApiVersion(_propagator->account()->capabilities().clientSideEncryptionVersion());
|
|
|
|
qCDebug(lcPropagateUploadEncrypted) << "Creating the encrypted file.";
|
|
|
|
if (info.isDir()) {
|
|
_completeFileName = encryptedFile.encryptedFilename;
|
|
} else {
|
|
QFile input(info.absoluteFilePath());
|
|
QFile output(QDir::tempPath() + QDir::separator() + encryptedFile.encryptedFilename);
|
|
|
|
QByteArray tag;
|
|
bool encryptionResult = EncryptionHelper::fileEncryption(encryptedFile.encryptionKey, encryptedFile.initializationVector, &input, &output, tag);
|
|
|
|
if (!encryptionResult) {
|
|
qCDebug(lcPropagateUploadEncrypted()) << "There was an error encrypting the file, aborting upload.";
|
|
emit error();
|
|
return;
|
|
}
|
|
|
|
encryptedFile.authenticationTag = tag;
|
|
_completeFileName = output.fileName();
|
|
}
|
|
|
|
qCDebug(lcPropagateUploadEncrypted) << "Creating the metadata for the encrypted file.";
|
|
|
|
metadata->addEncryptedFile(encryptedFile);
|
|
|
|
qCDebug(lcPropagateUploadEncrypted) << "Metadata created, sending to the server.";
|
|
|
|
connect(_encryptedFolderMetadataHandler.data(), &EncryptedFolderMetadataHandler::uploadFinished, this, &PropagateUploadEncrypted::slotUploadMetadataFinished);
|
|
_encryptedFolderMetadataHandler->uploadMetadata(EncryptedFolderMetadataHandler::UploadMode::KeepLock);
|
|
}
|
|
|
|
void PropagateUploadEncrypted::slotUploadMetadataFinished(int statusCode, const QString &message)
|
|
{
|
|
if (statusCode != 200) {
|
|
qCDebug(lcPropagateUploadEncrypted) << "Update metadata error for folder" << _encryptedFolderMetadataHandler->folderId() << "with error" << message;
|
|
qCDebug(lcPropagateUploadEncrypted()) << "Unlocking the folder.";
|
|
emit error();
|
|
return;
|
|
}
|
|
|
|
qCDebug(lcPropagateUploadEncrypted) << "Uploading of the metadata success, Encrypting the file";
|
|
QFileInfo outputInfo(_completeFileName);
|
|
|
|
qCDebug(lcPropagateUploadEncrypted) << "Encrypted Info:" << outputInfo.path() << outputInfo.fileName() << outputInfo.size();
|
|
qCDebug(lcPropagateUploadEncrypted) << "Finalizing the upload part, now the actuall uploader will take over";
|
|
emit finalized(Utility::trailingSlashPath(outputInfo.path()) + outputInfo.fileName(),
|
|
Utility::trailingSlashPath(_remoteParentPath) + outputInfo.fileName(),
|
|
FileSystem::getSize(_completeFileName));
|
|
}
|
|
|
|
} // namespace OCC
|