// SPDX-FileCopyrightText: 2022 Jonah BrĂ¼chert // SPDX-FileCopyrightText: 2022 Linus Jahn // // SPDX-License-Identifier: LGPL-2.1-or-later #include "QXmppEncryptedFileSharingProvider.h" #include "QXmppFileEncryption.h" #include "QXmppFileMetadata.h" #include "QXmppFileSharingManager.h" #include "QXmppFutureUtils_p.h" #include "QXmppUtils.h" #include "QcaInitializer_p.h" #include using namespace QXmpp; using namespace QXmpp::Private; /// /// \class QXmppEncryptedFileSharingProvider /// /// Encrypts or decrypts files on the fly when uploading or downloading. /// /// \since QXmpp 1.5 /// class QXmppEncryptedFileSharingProviderPrivate { public: QcaInitializer init; QXmppFileSharingManager *manager; std::shared_ptr uploadBaseProvider; }; /// /// \brief Create a new QXmppEncryptedFileSharingProvider /// /// \param manager QXmppFileSharingManager to be used to find other providers for downloading /// encrypted files. /// \param uploadBaseProvider Provider to be used for uploading the encrypted files. /// QXmppEncryptedFileSharingProvider::QXmppEncryptedFileSharingProvider( QXmppFileSharingManager *manager, std::shared_ptr uploadBaseProvider) : d(std::make_unique()) { d->manager = manager; d->uploadBaseProvider = std::move(uploadBaseProvider); } QXmppEncryptedFileSharingProvider::~QXmppEncryptedFileSharingProvider() = default; auto QXmppEncryptedFileSharingProvider::downloadFile(const std::any &source, std::unique_ptr target, std::function reportProgress, std::function reportFinished) -> std::shared_ptr { QXmppEncryptedFileSource encryptedSource; try { encryptedSource = std::any_cast(source); } catch (const std::bad_any_cast &) { qFatal("QXmppEncryptedFileSharingProvider::downloadFile can only handle QXmppEncryptedFileSource sources"); } auto output = std::make_unique(std::move(target), encryptedSource.cipher(), encryptedSource.iv(), encryptedSource.key()); // find provider for source of encrypted file std::any httpSource = encryptedSource.httpSources().front(); if (auto provider = d->manager->providerForSource(httpSource)) { return provider->downloadFile(httpSource, std::move(output), std::move(reportProgress), std::move(reportFinished)); } reportFinished(QXmppError { QStringLiteral("No basic file sharing provider available for encrypted file."), {} }); return {}; } auto QXmppEncryptedFileSharingProvider::uploadFile(std::unique_ptr data, const QXmppFileMetadata &, std::function reportProgress, std::function reportFinished) -> std::shared_ptr { auto cipher = Aes256CbcPkcs7; auto key = Encryption::generateKey(cipher); auto iv = Encryption::generateInitializationVector(cipher); auto encDevice = std::make_unique(std::move(data), cipher, key, iv); auto encryptedSize = encDevice->size(); QXmppFileMetadata metadata; metadata.setFilename(QXmppUtils::generateStanzaHash(10)); metadata.setMediaType(QMimeDatabase().mimeTypeForName("application/octet-stream")); metadata.setSize(encryptedSize); // find provider for source of encrypted file Q_ASSERT(d->uploadBaseProvider); return d->uploadBaseProvider->uploadFile( std::move(encDevice), metadata, std::move(reportProgress), [=, reportFinished = std::move(reportFinished)](UploadResult result) { auto encryptedResult = visitForward(std::move(result), [&](std::any httpSourceAny) { QXmppEncryptedFileSource encryptedSource; encryptedSource.setKey(key); encryptedSource.setIv(iv); encryptedSource.setHttpSources({ std::any_cast(std::move(httpSourceAny)) }); return encryptedSource; }); reportFinished(std::move(encryptedResult)); }); }