Skip to content

Add check for Content-Type when downloading tracker list #22137

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: master
Choose a base branch
from

Conversation

userwiths
Copy link
Contributor

@userwiths userwiths commented Jan 10, 2025

Closes #13061.

Description

Some users might get confused around platforms like github and their raw links. By mistake such user has entered the HTML page link and each HTML line was taken as a tracker.
In order to fix this issue, we add a check on the Content-Type header of the response. We accept text/plain and show a descriptive error message otherwise.

@glassez
Copy link
Member

glassez commented Jan 10, 2025

Some users might get confused around platforms like github and their raw links. By mistake such user has entered the HTML page link and each HTML line was taken as a tracker.
In order to fix this issue, we add a check on the Content-Type header of the response. We accept text/plain and show a descriptive error message otherwise.

The plain text may also contain arbitrary/inappropriate data. Shouldn't the lines themselves be validated instead?

@userwiths
Copy link
Contributor Author

I thought that the text area was meant to be used in order to "preview" the url's a user was about to add.
But I agree that we could limit their chances of entering gibberish accidentally.
Latest commit adds a simple check to see if the text looks like a url.

@glassez glassez changed the title fix: Add check for Content-Type when downloading tracker list. Add check for Content-Type when downloading tracker list Jan 10, 2025
@stalkerok
Copy link
Contributor

stalkerok commented Jan 10, 2025

Doesn't work, incorrect list added without a problem.
Working.
2025-01-11_000558
But it looks like you need to add checking here as well.
2025-01-10_234802

@userwiths userwiths requested a review from Chocobo1 January 13, 2025 16:34
@stalkerok
Copy link
Contributor

Tested!

Copy link

This PR is stale because it has been 60 days with no activity. This PR will be automatically closed within 7 days if there is no further activity.

@github-actions github-actions bot added the Stale label Mar 29, 2025
@userwiths
Copy link
Contributor Author

@stalkerok @glassez
I see that there is a stale-bot, I'm wondering if there is anything I could do in order to close this PR "naturally" (Merged or Closed due to issues) or keep it open until then, rather than have the bot close it automatically.

@github-actions github-actions bot removed the Stale label Mar 30, 2025
@luzpaz
Copy link
Contributor

luzpaz commented Mar 30, 2025

What's left to do here ?

@userwiths
Copy link
Contributor Author

A review maybe.
Don't know if this comment (#22137 (comment)) counts as such or not.

@xavier2k6 xavier2k6 requested a review from a team March 31, 2025 08:22
Copy link
Member

@glassez glassez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps I haven't identified all the problems yet...

Comment on lines 107 to 110
QByteArray data;
Path filePath;
QString magnetURI;
QString contentType;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
QByteArray data;
Path filePath;
QString magnetURI;
QString contentType;
QString contentType;
QByteArray data;
Path filePath;
QString magnetURI;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fields were reordered as requested, contentType appears right before data

@@ -83,6 +83,7 @@
#include "watchedfolderoptionsdialog.h"
#include "watchedfoldersmodel.h"
#include "webui/webui.h"
#include "base/net/downloadmanager.h"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrong order.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is even redundant since it is included in optionsdialog.h.

@@ -1229,8 +1230,42 @@ void OptionsDialog::saveBittorrentTabOptions() const
session->setAddTrackersEnabled(m_ui->checkEnableAddTrackers->isChecked());
session->setAdditionalTrackers(m_ui->textTrackers->toPlainText());

auto enabledAddTrackers = m_ui->checkAddTrackersFromURL->isChecked();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
auto enabledAddTrackers = m_ui->checkAddTrackersFromURL->isChecked();
const bool isAddTrackersEnabled = m_ui->checkAddTrackersFromURL->isChecked();

@@ -1229,8 +1230,42 @@ void OptionsDialog::saveBittorrentTabOptions() const
session->setAddTrackersEnabled(m_ui->checkEnableAddTrackers->isChecked());
session->setAdditionalTrackers(m_ui->textTrackers->toPlainText());

auto enabledAddTrackers = m_ui->checkAddTrackersFromURL->isChecked();
auto url = m_ui->textTrackersURL->text();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
auto url = m_ui->textTrackersURL->text();
const QString url = m_ui->textTrackersURL->text();

@@ -1229,8 +1230,42 @@ void OptionsDialog::saveBittorrentTabOptions() const
session->setAddTrackersEnabled(m_ui->checkEnableAddTrackers->isChecked());
session->setAdditionalTrackers(m_ui->textTrackers->toPlainText());

auto enabledAddTrackers = m_ui->checkAddTrackersFromURL->isChecked();
auto url = m_ui->textTrackersURL->text();
if (!url.isEmpty() && enabledAddTrackers)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't it more logical to check whether the feature is enabled first?

Suggested change
if (!url.isEmpty() && enabledAddTrackers)
if (isAddTrackersEnabled && !url.isEmpty())

{
if (endpoint.isEmpty())
return 0;
QUrl url(endpoint.toString());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
QUrl url(endpoint.toString());
const QUrl url {endpoint.toString()};

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed it, should be ok now.

void TrackersAdditionDialog::onAccepted() const
{
const QList<BitTorrent::TrackerEntryStatus> currentTrackers = m_torrent->trackers();
const int baseTier = !currentTrackers.isEmpty() ? (currentTrackers.last().tier + 1) : 0;

QList<BitTorrent::TrackerEntry> entries = BitTorrent::parseTrackerEntries(m_ui->textEditTrackersList->toPlainText());
for (BitTorrent::TrackerEntry &entry : entries)
for (BitTorrent::TrackerEntry &entry : entries) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Broken coding style.

Suggested change
for (BitTorrent::TrackerEntry &entry : entries) {
for (BitTorrent::TrackerEntry &entry : entries)
{

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

void TrackersAdditionDialog::onAccepted() const
{
const QList<BitTorrent::TrackerEntryStatus> currentTrackers = m_torrent->trackers();
const int baseTier = !currentTrackers.isEmpty() ? (currentTrackers.last().tier + 1) : 0;

QList<BitTorrent::TrackerEntry> entries = BitTorrent::parseTrackerEntries(m_ui->textEditTrackersList->toPlainText());
for (BitTorrent::TrackerEntry &entry : entries)
for (BitTorrent::TrackerEntry &entry : entries) {
auto isValid = isValidEndpoint(entry.url);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems this variable doesn't make much sense.

Suggested change
auto isValid = isValidEndpoint(entry.url);
if (isValidEndpoint(entry.url))

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, you are right, addressed.

auto isValid = isValidEndpoint(entry.url);
if (!isValid)
{
QMessageBox::warning(const_cast<TrackersAdditionDialog *>(this), tr("Invalid tracker URL"), tr("The tracker URL \"%1\" is invalid").arg(entry.url));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would drop const specifier from onAccepted() than use const_cast here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure thing, done.

@@ -65,6 +65,7 @@ private slots:
private:
void saveSettings();
void loadSettings();
int isValidEndpoint(const QStringView &endpoint) const;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function is independent of TrackersAdditionDialog class, so it can be declared in an anonymous namespace in the trackersadditiondialog.cpp file.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair enough, made it an anonymous function.

@userwiths userwiths force-pushed the fix/download-tracker-list-content-type-check-13061 branch from c87669f to bc8c6bb Compare March 31, 2025 13:00
@userwiths
Copy link
Contributor Author

Ok, all points should be covered now, even those on which I did not comment.

In case there is anything else, feel free to send it my way, im gonna take a look as soon as possible.

PS: thx for the time.

@userwiths userwiths requested a review from glassez March 31, 2025 13:52
if (isAddTrackersEnabled && !url.isEmpty())
{
Net::DownloadManager::instance()->download(url, Preferences::instance()->useProxyForGeneralPurposes()
, this, &OptionsDialog::onAdditionalTrackersDownload);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
, this, &OptionsDialog::onAdditionalTrackersDownload);
, this, &OptionsDialog::onAdditionalTrackersDownloadFinished);

@glassez
Copy link
Member

glassez commented Apr 1, 2025

Well, here's my general review.

I have no particular complaints about the TrackersAdditionDialog.

As for the main option, its processing is done in a dubious way, IMO.
To begin with, it would be more correct to check downloaded trackers list directly in the place where it is processed by the BitTorrent Session, and reject unsuitable data with a message entry in the log.
A preliminary check in the Options dialog may look like a good idea, but it is not implemented correctly. IMO, it is a bad idea to initiate data downloading when applying options. Wouldn't it be better to add a "Test" button to do this explicitly? Otherwise, we have two cases:

  1. The user clicked the "Apply" button. In this case, there is a chance that user will see a corresponding message about an unsuccessful download of trackers.
  2. The user clicked the "Ok" button which closes the dialog immediatelly after applying the options. This is at least a race condition. Most likely, the user will not receive any message at all, since the dialog will be destroyed before that.

@userwiths userwiths force-pushed the fix/download-tracker-list-content-type-check-13061 branch from 9f9ff75 to 5567d02 Compare May 12, 2025 10:17
@userwiths
Copy link
Contributor Author

Hey, I failed to get back to this sooner, but now it should be as you described.

I went with the message box implementation earlier thinking it would be easier for users to understand when/what happens.
I removed the changes done by me to the optionsdialog files.
Now the check is done in sessionimpl and we log a message describing the expected and the received Content-Type in case of mismatch.

If there's anything else I can refine, leave a comment and im gonna take a look at it.

@userwiths userwiths requested a review from glassez May 12, 2025 11:06
Copy link

This PR is stale because it has been 60 days with no activity. This PR will be automatically closed within 7 days if there is no further activity.

@github-actions github-actions bot added the Stale label Jul 12, 2025
@userwiths
Copy link
Contributor Author

@glassez (pinging cause last reviewer/commenter)

I don't mean to bother, but would hate the bot to auto close a possible fix.

@xavier2k6 xavier2k6 requested a review from a team July 12, 2025 18:23
@xavier2k6
Copy link
Member

Review pending........

@github-actions github-actions bot removed the Stale label Jul 13, 2025
@@ -74,14 +74,35 @@ TrackersAdditionDialog::~TrackersAdditionDialog()
delete m_ui;
}

void TrackersAdditionDialog::onAccepted() const
bool isValidEndpoint(const QStringView endpoint)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function should be placed inside anonymous namespace above TrackersAdditionDialog definitions.

if (!isValidEndpoint(entry.url))
{
QMessageBox::warning(this, tr("Invalid tracker URL"), tr("The tracker URL \"%1\" is invalid").arg(entry.url));
return;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, it looks unfriendly if you reject all the entered trackers because of invalid one. Or am I misunderstood it?

@@ -4105,6 +4105,11 @@ void SessionImpl::updateTrackersFromURL()
{
if (result.status == Net::DownloadStatus::Success)
{
if (!result.contentType.contains(u"text/plain"_s, Qt::CaseInsensitive))
{
LogMsg(tr("Cannot add trackers from URL, expected Content-Type is \'text/plain\' received \"%1\"").arg(result.contentType), Log::WARNING);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Single and double quotes are used inconsistently in this message.
  2. I doubt that single quotes need to be escaped.
  3. The message format seems inappropriate (and even grammatically invalid).

@Chocobo1?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Perform a check when adding an incompatible list URL
6 participants