#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 #include #include #include #include #include #include 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 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