diff options
author | Tobias Fella <fella@posteo.de> | 2022-03-08 00:06:36 +0100 |
---|---|---|
committer | Tobias Fella <fella@posteo.de> | 2022-05-16 20:47:17 +0200 |
commit | efa450920e5fc338e771e653ca0889e948d04ee7 (patch) | |
tree | 215efb53d0e06ed660a97593d56ffb4868dbc2e2 /lib/room.cpp | |
parent | 6f5ac9b7315d75692960e5eac7b1eb6867c0d203 (diff) | |
download | libquotient-efa450920e5fc338e771e653ca0889e948d04ee7.tar.gz libquotient-efa450920e5fc338e771e653ca0889e948d04ee7.zip |
Implement sending encrypted files
Diffstat (limited to 'lib/room.cpp')
-rw-r--r-- | lib/room.cpp | 67 |
1 files changed, 44 insertions, 23 deletions
diff --git a/lib/room.cpp b/lib/room.cpp index 7db9f8e9..763ca31c 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -299,8 +299,7 @@ public: RoomEvent* addAsPending(RoomEventPtr&& event); - //TODO deleteWhenFinishedis ugly, find out if there's something nicer - QString doSendEvent(const RoomEvent* pEvent, bool deleteWhenFinished = false); + QString doSendEvent(const RoomEvent* pEvent); void onEventSendingFailure(const QString& txnId, BaseJob* call = nullptr); SetRoomStateWithKeyJob* requestSetState(const QString& evtType, @@ -2076,6 +2075,16 @@ QString Room::Private::sendEvent(RoomEventPtr&& event) qCWarning(MAIN) << q << "has been upgraded, event won't be sent"; return {}; } + + return doSendEvent(addAsPending(std::move(event))); +} + +QString Room::Private::doSendEvent(const RoomEvent* pEvent) +{ + const auto txnId = pEvent->transactionId(); + // TODO, #133: Enqueue the job rather than immediately trigger it. + const RoomEvent* _event = pEvent; + if (q->usesEncryption()) { if (!hasValidMegolmSession() || shouldRotateMegolmSession()) { createMegolmSession(); @@ -2083,10 +2092,8 @@ QString Room::Private::sendEvent(RoomEventPtr&& event) const auto devicesWithoutKey = getDevicesWithoutKey(); sendMegolmSession(devicesWithoutKey); - //TODO check if this is necessary //TODO check if we increment the sent message count - event->setRoomId(id); - const auto encrypted = currentOutboundMegolmSession->encrypt(QJsonDocument(event->fullJson()).toJson()); + const auto encrypted = currentOutboundMegolmSession->encrypt(QJsonDocument(pEvent->fullJson()).toJson()); currentOutboundMegolmSession->setMessageCount(currentOutboundMegolmSession->messageCount() + 1); connection->saveCurrentOutboundMegolmSession(q, currentOutboundMegolmSession); if(std::holds_alternative<QOlmError>(encrypted)) { @@ -2098,23 +2105,14 @@ QString Room::Private::sendEvent(RoomEventPtr&& event) encryptedEvent->setTransactionId(connection->generateTxnId()); encryptedEvent->setRoomId(id); encryptedEvent->setSender(connection->userId()); - event->setTransactionId(encryptedEvent->transactionId()); // We show the unencrypted event locally while pending. The echo check will throw the encrypted version out - addAsPending(std::move(event)); - return doSendEvent(encryptedEvent, true); + _event = encryptedEvent; } - return doSendEvent(addAsPending(std::move(event))); -} - -QString Room::Private::doSendEvent(const RoomEvent* pEvent, bool deleteWhenFinished) -{ - const auto txnId = pEvent->transactionId(); - // TODO, #133: Enqueue the job rather than immediately trigger it. if (auto call = connection->callApi<SendMessageJob>(BackgroundRequest, id, - pEvent->matrixType(), txnId, - pEvent->contentJson())) { + _event->matrixType(), txnId, + _event->contentJson())) { Room::connect(call, &BaseJob::sentRequest, q, [this, txnId] { auto it = q->findPendingEvent(txnId); if (it == unsyncedEvents.end()) { @@ -2128,7 +2126,7 @@ QString Room::Private::doSendEvent(const RoomEvent* pEvent, bool deleteWhenFinis Room::connect(call, &BaseJob::failure, q, std::bind(&Room::Private::onEventSendingFailure, this, txnId, call)); - Room::connect(call, &BaseJob::success, q, [this, call, txnId, deleteWhenFinished, pEvent] { + Room::connect(call, &BaseJob::success, q, [this, call, txnId, _event] { auto it = q->findPendingEvent(txnId); if (it != unsyncedEvents.end()) { if (it->deliveryStatus() != EventStatus::ReachedServer) { @@ -2140,8 +2138,8 @@ QString Room::Private::doSendEvent(const RoomEvent* pEvent, bool deleteWhenFinis << "already merged"; emit q->messageSent(txnId, call->eventId()); - if (deleteWhenFinished){ - delete pEvent; + if (q->usesEncryption()){ + delete _event; } }); } else @@ -2266,13 +2264,16 @@ QString Room::Private::doPostFile(RoomEventPtr&& msgEvent, const QUrl& localUrl) // Below, the upload job is used as a context object to clean up connections const auto& transferJob = fileTransfers.value(txnId).job; connect(q, &Room::fileTransferCompleted, transferJob, - [this, txnId](const QString& tId, const QUrl&, const QUrl& mxcUri) { + [this, txnId](const QString& tId, const QUrl&, const QUrl& mxcUri, Omittable<EncryptedFile> encryptedFile) { if (tId != txnId) return; const auto it = q->findPendingEvent(txnId); if (it != unsyncedEvents.end()) { it->setFileUploaded(mxcUri); + if (encryptedFile) { + it->setEncryptedFile(*encryptedFile); + } emit q->pendingEventChanged( int(it - unsyncedEvents.begin())); doSendEvent(it->get()); @@ -2508,6 +2509,20 @@ void Room::uploadFile(const QString& id, const QUrl& localFilename, Q_ASSERT_X(localFilename.isLocalFile(), __FUNCTION__, "localFilename should point at a local file"); auto fileName = localFilename.toLocalFile(); + Omittable<EncryptedFile> encryptedFile = std::nullopt; +#ifdef Quotient_E2EE_ENABLED + QTemporaryFile tempFile; + if (usesEncryption()) { + tempFile.open(); + QFile file(localFilename.toLocalFile()); + file.open(QFile::ReadOnly); + auto [e, data] = EncryptedFile::encryptFile(file.readAll()); + tempFile.write(data); + tempFile.close(); + fileName = QFileInfo(tempFile).absoluteFilePath(); + encryptedFile = e; + } +#endif auto job = connection()->uploadFile(fileName, overrideContentType); if (isJobPending(job)) { d->fileTransfers[id] = { job, fileName, true }; @@ -2516,9 +2531,15 @@ void Room::uploadFile(const QString& id, const QUrl& localFilename, d->fileTransfers[id].update(sent, total); emit fileTransferProgress(id, sent, total); }); - connect(job, &BaseJob::success, this, [this, id, localFilename, job] { + connect(job, &BaseJob::success, this, [this, id, localFilename, job, encryptedFile] { d->fileTransfers[id].status = FileTransferInfo::Completed; - emit fileTransferCompleted(id, localFilename, QUrl(job->contentUri())); + if (encryptedFile) { + auto file = *encryptedFile; + file.url = QUrl(job->contentUri()); + emit fileTransferCompleted(id, localFilename, QUrl(job->contentUri()), file); + } else { + emit fileTransferCompleted(id, localFilename, QUrl(job->contentUri())); + } }); connect(job, &BaseJob::failure, this, std::bind(&Private::failedTransfer, d, id, job->errorString())); |