Skip to content

Commit

Permalink
Move image uploader success messages to MessageBuilder
Browse files Browse the repository at this point in the history
Bonus feature: this doesn't trigger link resolver both preventing
leaking the delete link to the api and now the API can't know who
uploaded what image based on timing.
  • Loading branch information
Mm2PL committed Nov 18, 2023
1 parent bf4fc8c commit 5c00d0d
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 19 deletions.
57 changes: 57 additions & 0 deletions src/messages/MessageBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "controllers/accounts/AccountController.hpp"
#include "messages/Image.hpp"
#include "messages/Message.hpp"
#include "messages/MessageColor.hpp"
#include "messages/MessageElement.hpp"
#include "providers/LinkResolver.hpp"
#include "providers/twitch/PubSubActions.hpp"
Expand Down Expand Up @@ -660,6 +661,62 @@ MessageBuilder::MessageBuilder(LiveUpdatesUpdateEmoteSetMessageTag /*unused*/,
this->message().flags.set(MessageFlag::DoNotTriggerNotification);
}

MessageBuilder::MessageBuilder(ImageUploaderResultTag /*unused*/,
const QString &imageLink,
const QString &deletionLink,
size_t imagesStillQueued, size_t secondsLeft)
: MessageBuilder()
{
this->message().flags.set(MessageFlag::System);
this->message().flags.set(MessageFlag::DoNotTriggerNotification);

this->emplace<TimestampElement>();

using MEF = MessageElementFlag;
auto addText = [this](QString text, MessageElementFlags mefs = MEF::Text,
MessageColor color =
MessageColor::System) -> TextElement * {
this->message().searchText += text;
this->message().messageText += text;
return this->emplace<TextElement>(text, mefs, color);
};

addText("Your image has been uploaded to");

// ASSUMPTION: the user gave this uploader configuration to the program
// therefore they trust that the host is not wrong/malicious. This doesn't obey getSettings()->lowercaseDomains.
// This also ensures that the LinkResolver doesn't get these links.
addText(imageLink,
MessageElementFlags(MEF::OriginalLink) |
MessageElementFlags(MEF::LowercaseLink),
MessageColor::Link)
->setLink({Link::Url, imageLink})
->setTrailingSpace(false);

if (!deletionLink.isEmpty())
{
addText("(Deletion link:");
addText(deletionLink,
MessageElementFlags(MEF::OriginalLink) |
MessageElementFlags(MEF::LowercaseLink),
MessageColor::Link)
->setLink({Link::Url, deletionLink})
->setTrailingSpace(false);
addText(")")->setTrailingSpace(false);
}
addText(".");

if (imagesStillQueued == 0)
{
return;
}

addText(QString("%1 left. Please wait until all of them are uploaded. "
"About %2 seconds left.")
.arg(imagesStillQueued)
.arg(secondsLeft));
}

Message *MessageBuilder::operator->()
{
return this->message_.get();
Expand Down
17 changes: 17 additions & 0 deletions src/messages/MessageBuilder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,20 @@ struct LiveUpdatesAddEmoteMessageTag {
};
struct LiveUpdatesUpdateEmoteSetMessageTag {
};
struct ImageUploaderResultTag {
};

const SystemMessageTag systemMessage{};
const TimeoutMessageTag timeoutMessage{};
const LiveUpdatesUpdateEmoteMessageTag liveUpdatesUpdateEmoteMessage{};
const LiveUpdatesRemoveEmoteMessageTag liveUpdatesRemoveEmoteMessage{};
const LiveUpdatesAddEmoteMessageTag liveUpdatesAddEmoteMessage{};
const LiveUpdatesUpdateEmoteSetMessageTag liveUpdatesUpdateEmoteSetMessage{};

// This signifies that you want to construct a message containing the result of
// a successful image upload.
const ImageUploaderResultTag imageUploaderResultMessage{};

MessagePtr makeSystemMessage(const QString &text);
MessagePtr makeSystemMessage(const QString &text, const QTime &time);
std::pair<MessagePtr, MessagePtr> makeAutomodMessage(
Expand Down Expand Up @@ -88,6 +95,16 @@ class MessageBuilder
MessageBuilder(LiveUpdatesUpdateEmoteSetMessageTag, const QString &platform,
const QString &actor, const QString &emoteSetName);

/**
* "Your image has been uploaded to %1[ (Delection link: %2)]."
* or "Your image has been uploaded to %1 %2. %3 left. "
* "Please wait until all of them are uploaded. "
* "About %4 seconds left."
*/
MessageBuilder(ImageUploaderResultTag, const QString &imageLink,
const QString &deletionLink, size_t imagesStillQueued = 0,
size_t secondsLeft = 0);

virtual ~MessageBuilder() = default;

Message *operator->();
Expand Down
28 changes: 9 additions & 19 deletions src/singletons/ImageUploader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "common/NetworkRequest.hpp"
#include "common/NetworkResult.hpp"
#include "common/QLogging.hpp"
#include "messages/MessageBuilder.hpp"
#include "providers/twitch/TwitchMessageBuilder.hpp"
#include "singletons/Paths.hpp"
#include "singletons/Settings.hpp"
Expand Down Expand Up @@ -216,31 +217,20 @@ void ImageUploader::handleSuccessfulUpload(const NetworkResult &result,
getSettings()->imageUploaderDeletionLink);
qCDebug(chatterinoImageuploader) << link << deletionLink;
textEdit.insertPlainText(link + " ");

// 2 seconds for the timer that's there not to spam the remote server
// and 1 second of actual uploading.
auto timeToUpload = this->uploadQueue_.size() * (UPLOAD_DELAY / 1000 + 1);
MessageBuilder builder =
MessageBuilder(imageUploaderResultMessage, link, deletionLink,
this->uploadQueue_.size(), timeToUpload);
channel->addMessage(builder.release());
if (this->uploadQueue_.empty())
{
channel->addMessage(makeSystemMessage(
QString("Your image has been uploaded to %1 %2.")
.arg(link)
.arg(deletionLink.isEmpty()
? ""
: QString("(Deletion link: %1 )").arg(deletionLink))));
this->uploadMutex_.unlock();
}
else
{
channel->addMessage(makeSystemMessage(
QString("Your image has been uploaded to %1 %2. %3 left. "
"Please wait until all of them are uploaded. "
"About %4 seconds left.")
.arg(link)
.arg(deletionLink.isEmpty()
? ""
: QString("(Deletion link: %1 )").arg(deletionLink))
.arg(this->uploadQueue_.size())
.arg(this->uploadQueue_.size() * (UPLOAD_DELAY / 1000 + 1))));
// 2 seconds for the timer that's there not to spam the remote server
// and 1 second of actual uploading.

QTimer::singleShot(UPLOAD_DELAY, [channel, &textEdit, this]() {
this->sendImageUploadRequest(this->uploadQueue_.front(), channel,
textEdit);
Expand Down

0 comments on commit 5c00d0d

Please sign in to comment.