// SPDX-FileCopyrightText: 2022 Jonah BrĂ¼chert // // SPDX-License-Identifier: LGPL-2.1-or-later #include "QXmppEncryptedHttpFileSharingProvider.h" #include "QXmppClient.h" #include "QXmppFileEncryption.h" #include "QXmppHttpUploadManager.h" #include "QXmppUpload.h" #include "QXmppUtils.h" #include "QcaInitializer_p.h" #include using namespace QXmpp; using namespace QXmpp::Private; class QXmppSfsEncryptedHttpUpload : public QXmppUpload { Q_OBJECT public: QXmppSfsEncryptedHttpUpload(std::shared_ptr &&httpUpload, const QByteArray &key, const QByteArray &iv) : inner(std::move(httpUpload)) { connect(inner.get(), &QXmppHttpUpload::finished, this, [=](const QXmppHttpUpload::Result &result) { Q_EMIT uploadFinished(std::visit([=](auto &&value) -> QXmpp::Private::UploadResult { using T = std::decay_t; if constexpr (std::is_same_v) { QXmppEncryptedFileSource encryptedSource; encryptedSource.setKey(key); encryptedSource.setIv(iv); encryptedSource.setHttpSources({ QXmppHttpFileSource(value) }); return std::any(encryptedSource); } else if constexpr (std::is_same_v) { return Cancelled {}; } else if constexpr (std::is_same_v) { return value; } }, result)); }); } float progress() override { return inner->progress(); } void cancel() override { inner->cancel(); } bool isFinished() override { return inner->isFinished(); } quint64 bytesTransferred() override { return inner->bytesSent(); } quint64 bytesTotal() override { return inner->bytesTotal(); } private: std::shared_ptr inner; }; /// /// \class QXmppEncryptedHttpFileSharingProvider /// /// Support for storing files encrypted on an HTTP server /// /// \since QXmpp 1.5 /// class QXmppEncryptedHttpFileSharingProviderPrivate { public: QXmpp::Private::QcaInitializer init; QXmppHttpUploadManager *manager; QXmppHttpFileSharingProvider *httpProvider; }; /// /// \brief Create a new QXmppEncryptedHttpFileSharingProvider /// \param client /// \param netManager QNetworkAccessManager that can be reused all over your application. /// QXmppEncryptedHttpFileSharingProvider::QXmppEncryptedHttpFileSharingProvider(QXmppClient *client, QNetworkAccessManager *netManager) : d(std::make_unique()) { qRegisterMetaType(); Q_ASSERT(client); d->manager = client->findExtension(); Q_ASSERT(d->manager); d->httpProvider = new QXmppHttpFileSharingProvider(client, netManager); } QXmppEncryptedHttpFileSharingProvider::~QXmppEncryptedHttpFileSharingProvider() = default; std::shared_ptr QXmppEncryptedHttpFileSharingProvider::downloadFile(const std::any &source, std::unique_ptr &&target) { QXmppEncryptedFileSource encryptedSource; try { encryptedSource = std::any_cast(source); } catch (const std::bad_any_cast &) { qFatal("QXmppEncryptedHttpFileSharingProvider::downloadFile can only handle QXmppEncryptedFileSource sources"); } auto httpSource = encryptedSource.httpSources().front(); auto output = std::make_unique(std::move(target), encryptedSource.cipher(), encryptedSource.iv(), encryptedSource.key()); return d->httpProvider->downloadFile(httpSource, std::move(output)); } std::shared_ptr QXmppEncryptedHttpFileSharingProvider::uploadFile( std::unique_ptr data, const QXmppFileMetadata &info) { 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(); auto upload = d->manager->uploadFile( std::move(encDevice), QXmppUtils::generateStanzaHash(10), QMimeDatabase().mimeTypeForName("application/octet-stream"), encryptedSize); return std::make_shared(std::move(upload), key, iv); } #include "QXmppEncryptedHttpFileSharingProvider.moc"