Remove the web torrent code from brave-core (#29320)

* Remove the web torrent code from brave-core

Fixes https://github.com/brave/brave-browser/issues/46430

Includes manual adjustment for `resources/resource_ids.spec`
This commit is contained in:
Brian Clifton
2025-06-24 19:11:59 +02:00
committed by GitHub
parent 4c96af5e19
commit cfa161e90d
111 changed files with 57 additions and 6959 deletions
-1
View File
@@ -15,7 +15,6 @@ vendor/omaha/
/.idea/
/components/brave_new_tab_ui/data/LICENSE
/components/brave_wallet/browser/zcash/rust/librustzcash/src/
/components/brave_webtorrent/extension/out/
/components/brave_rewards/resources/extension/brave_rewards/out/
/components/third_party/adblock/LICENSE
/components/third_party/local_data/LICENSE
-1
View File
@@ -77,7 +77,6 @@ components/brave_wallet/resources/solana_web3_script.js
/components/policy/resources/templates/
/components/playlist/
/components/speedreader/
/components/brave_webtorrent/
/components/common/
/components/cosmetic_filters/
/components/definitions/
-7
View File
@@ -3,7 +3,6 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at https://mozilla.org/MPL/2.0/.
import("//brave/components/brave_webtorrent/browser/buildflags/buildflags.gni")
import("//brave/components/tor/buildflags/buildflags.gni")
import("//build/config/locales.gni")
import("//chrome/common/features.gni")
@@ -89,12 +88,6 @@ template("brave_extra_paks") {
deps += [ "//brave/components/tor/resources" ]
}
if (enable_brave_webtorrent) {
sources += [ "$root_gen_dir/brave/components/brave_webtorrent/brave_webtorrent_resources.pak" ]
deps += [ "//brave/components/brave_webtorrent:resources" ]
}
if (enable_extensions) {
sources += [ "$root_gen_dir/brave/components/brave_extension/brave_extension_resources.pak" ]
-1
View File
@@ -84,7 +84,6 @@ include_rules += [
"+brave/components/body_sniffer",
"+brave/components/brave_search/browser",
"+brave/components/brave_search/common",
"+brave/components/brave_webtorrent/browser",
"+brave/components/cosmetic_filters/browser",
"+brave/components/cosmetic_filters/common",
"+brave/components/decentralized_dns/content",
-11
View File
@@ -81,7 +81,6 @@
#include "brave/components/brave_wallet/browser/brave_wallet_utils.h"
#include "brave/components/brave_wallet/common/brave_wallet.mojom.h"
#include "brave/components/brave_wallet/common/common_utils.h"
#include "brave/components/brave_webtorrent/browser/buildflags/buildflags.h"
#include "brave/components/constants/pref_names.h"
#include "brave/components/constants/webui_url_constants.h"
#include "brave/components/containers/buildflags/buildflags.h"
@@ -192,10 +191,6 @@ using extensions::ChromeContentBrowserClientExtensionsPart;
#include "brave/components/ai_rewriter/common/mojom/ai_rewriter.mojom.h"
#endif
#if BUILDFLAG(ENABLE_BRAVE_WEBTORRENT)
#include "brave/browser/extensions/brave_webtorrent_navigation_throttle.h"
#endif
#if BUILDFLAG(ENABLE_TOR)
#include "brave/browser/tor/tor_profile_service_factory.h"
#include "brave/components/tor/onion_location_navigation_throttle.h"
@@ -1175,12 +1170,6 @@ void BraveContentBrowserClient::CreateThrottlesForNavigation(
NewTabShowsNavigationThrottle::MaybeCreateAndAdd(registry);
#endif
#if BUILDFLAG(ENABLE_BRAVE_WEBTORRENT)
registry.AddThrottle(
std::make_unique<extensions::BraveWebTorrentNavigationThrottle>(
registry));
#endif
#if BUILDFLAG(ENABLE_TOR)
tor::TorNavigationThrottle::MaybeCreateAndAdd(registry, context->IsTor());
tor::OnionLocationNavigationThrottle::MaybeCreateAndAdd(
@@ -13,7 +13,6 @@
#include "base/strings/utf_string_conversions.h"
#include "base/test/bind.h"
#include "brave/components/brave_shields/core/common/brave_shield_constants.h"
#include "brave/components/brave_webtorrent/browser/buildflags/buildflags.h"
#include "brave/components/constants/brave_paths.h"
#include "brave/components/constants/pref_names.h"
#include "brave/components/constants/webui_url_constants.h"
@@ -49,10 +48,6 @@
#include "brave/net/proxy_resolution/proxy_config_service_tor.h"
#endif
#if BUILDFLAG(ENABLE_BRAVE_WEBTORRENT)
#include "brave/components/brave_webtorrent/browser/magnet_protocol_handler.h"
#endif
class BraveContentBrowserClientTest : public InProcessBrowserTest {
public:
void SetUp() override {
@@ -78,38 +73,6 @@ class BraveContentBrowserClientTest : public InProcessBrowserTest {
embedded_test_server()->ServeFilesFromDirectory(test_data_dir);
ASSERT_TRUE(embedded_test_server()->Start());
magnet_html_url_ = embedded_test_server()->GetURL("a.com", "/magnet.html");
magnet_url_ = GURL(
"magnet:?xt=urn:btih:dd8255ecdc7ca55fb0bbf81323d87062db1f6d1c&dn=Big+"
"Buck+Bunny&tr=udp%3A%2F%2Fexplodie.org%3A6969&tr=udp%3A%2F%2Ftracker."
"coppersurfer.tk%3A6969&tr=udp%3A%2F%2Ftracker.empire-js.us%3A1337&tr="
"udp%3A%2F%2Ftracker.leechers-paradise.org%3A6969&tr=udp%3A%2F%"
"2Ftracker.opentrackr.org%3A1337&tr=wss%3A%2F%2Ftracker.btorrent.xyz&"
"tr=wss%3A%2F%2Ftracker.fastcast.nz&tr=wss%3A%2F%2Ftracker."
"openwebtorrent.com&ws=https%3A%2F%2Fwebtorrent.io%2Ftorrents%2F&xs="
"https%3A%2F%2Fwebtorrent.io%2Ftorrents%2Fbig-buck-bunny.torrent");
extension_url_ = GURL(
"chrome-extension://lgjmpdmojkpocjcopdikifhejkkjglho/extension/"
"brave_webtorrent.html?magnet%3A%3Fxt%3Durn%3Abtih%"
"3Add8255ecdc7ca55fb0bbf81323d87062db1f6d1c%26dn%3DBig%2BBuck%2BBunny%"
"26tr%3Dudp%253A%252F%252Fexplodie.org%253A6969%26tr%3Dudp%253A%252F%"
"252Ftracker.coppersurfer.tk%253A6969%26tr%3Dudp%253A%252F%252Ftracker."
"empire-js.us%253A1337%26tr%3Dudp%253A%252F%252Ftracker.leechers-"
"paradise.org%253A6969%26tr%3Dudp%253A%252F%252Ftracker.opentrackr.org%"
"253A1337%26tr%3Dwss%253A%252F%252Ftracker.btorrent.xyz%26tr%3Dwss%"
"253A%252F%252Ftracker.fastcast.nz%26tr%3Dwss%253A%252F%252Ftracker."
"openwebtorrent.com%26ws%3Dhttps%253A%252F%252Fwebtorrent.io%"
"252Ftorrents%252F%26xs%3Dhttps%253A%252F%252Fwebtorrent.io%"
"252Ftorrents%252Fbig-buck-bunny.torrent");
torrent_url_ = GURL("https://webtorrent.io/torrents/sintel.torrent#ix=5");
torrent_extension_url_ = GURL(
"chrome-extension://lgjmpdmojkpocjcopdikifhejkkjglho/extension/"
"brave_webtorrent.html?https://webtorrent.io/torrents/"
"sintel.torrent#ix=5");
torrent_invalid_query_extension_url_ = GURL(
"chrome-extension://lgjmpdmojkpocjcopdikifhejkkjglho/extension/"
"brave_webtorrent.html?chrome://settings");
}
void TearDown() override { browser_content_client_.reset(); }
@@ -127,26 +90,11 @@ class BraveContentBrowserClientTest : public InProcessBrowserTest {
EXPECT_EQ(contents->GetLastCommittedURL(), final_url);
}
const GURL& magnet_html_url() { return magnet_html_url_; }
const GURL& magnet_url() { return magnet_url_; }
const GURL& extension_url() { return extension_url_; }
const GURL& torrent_url() { return torrent_url_; }
const GURL& torrent_extension_url() { return torrent_extension_url_; }
const GURL& torrent_invalid_query_extension_url() {
return torrent_invalid_query_extension_url_;
}
content::ContentBrowserClient* client() {
return browser_content_client_.get();
}
private:
GURL magnet_html_url_;
GURL magnet_url_;
GURL extension_url_;
GURL torrent_url_;
GURL torrent_extension_url_;
GURL torrent_invalid_query_extension_url_;
std::unique_ptr<BraveContentBrowserClient> browser_content_client_;
};
@@ -288,244 +236,6 @@ IN_PROC_BROWSER_TEST_F(BraveContentBrowserClientTest, RewriteAdblock) {
}
}
#if BUILDFLAG(ENABLE_BRAVE_WEBTORRENT)
IN_PROC_BROWSER_TEST_F(BraveContentBrowserClientTest, RewriteMagnetURLURLBar) {
browser()->profile()->GetPrefs()->SetBoolean(kWebTorrentEnabled, true);
content::WebContents* contents =
browser()->tab_strip_model()->GetActiveWebContents();
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), magnet_url()));
ASSERT_TRUE(WaitForLoadStop(contents));
EXPECT_EQ(contents->GetLastCommittedURL().spec(), magnet_url().spec())
<< "URL visible to users should stay as the magnet URL";
content::NavigationEntry* entry =
contents->GetController().GetLastCommittedEntry();
EXPECT_EQ(entry->GetURL().spec(), extension_url().spec())
<< "Real URL should be extension URL";
}
IN_PROC_BROWSER_TEST_F(BraveContentBrowserClientTest, RewriteMagnetURLLink) {
browser()->profile()->GetPrefs()->SetBoolean(kWebTorrentEnabled, true);
content::WebContents* contents =
browser()->tab_strip_model()->GetActiveWebContents();
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), magnet_html_url()));
ASSERT_TRUE(WaitForLoadStop(contents));
EXPECT_TRUE(content::ExecJs(contents, "clickMagnetLink();"));
// Magnet protocol handler posts to UIThreadTaskRunner, so let all tasks run,
// otherwise WaitForLoadStop may return right away.
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(WaitForLoadStop(contents));
EXPECT_EQ(contents->GetLastCommittedURL().spec(), magnet_url().spec())
<< "URL visible to users should stay as the magnet URL";
content::NavigationEntry* entry =
contents->GetController().GetLastCommittedEntry();
EXPECT_EQ(entry->GetURL().spec(), extension_url().spec())
<< "Real URL should be extension URL";
}
IN_PROC_BROWSER_TEST_F(BraveContentBrowserClientTest, TypedMagnetURL) {
browser()->profile()->GetPrefs()->SetBoolean(kWebTorrentEnabled, true);
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
ui_test_utils::SendToOmniboxAndSubmit(browser(), magnet_url().spec());
// Magnet protocol handler posts to UIThreadTaskRunner, so let all tasks run,
// otherwise WaitForLoadStop may return right away.
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(WaitForLoadStop(web_contents));
EXPECT_EQ(magnet_url(), web_contents->GetLastCommittedURL().spec());
}
IN_PROC_BROWSER_TEST_F(BraveContentBrowserClientTest,
ReverseRewriteTorrentURL) {
browser()->profile()->GetPrefs()->SetBoolean(kWebTorrentEnabled, true);
content::WebContents* contents =
browser()->tab_strip_model()->GetActiveWebContents();
// Used to add the extension
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), magnet_url()));
ASSERT_TRUE(WaitForLoadStop(contents));
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), torrent_extension_url()));
ASSERT_TRUE(WaitForLoadStop(contents));
EXPECT_EQ(contents->GetLastCommittedURL().spec(),
base::StrCat({url::kWebTorrentScheme, ":", torrent_url().spec()}))
<< "URL visible to users should stay as the torrent URL";
content::NavigationEntry* entry =
contents->GetController().GetLastCommittedEntry();
EXPECT_EQ(entry->GetURL().spec(), torrent_extension_url().spec())
<< "Real URL should be extension URL";
}
IN_PROC_BROWSER_TEST_F(BraveContentBrowserClientTest,
MagnetIframeWithUserGestureOpensWebtorrent) {
browser()->profile()->GetPrefs()->SetBoolean(kWebTorrentEnabled, true);
content::WebContents* contents =
browser()->tab_strip_model()->GetActiveWebContents();
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), magnet_html_url()));
EXPECT_TRUE(content::ExecJs(contents, "createMagnetIframe(false);"));
// Magnet protocol handler posts to UIThreadTaskRunner, so let all tasks run,
// otherwise WaitForLoadStop may return right away.
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(WaitForLoadStop(contents));
EXPECT_EQ(contents->GetLastCommittedURL(), magnet_url());
}
IN_PROC_BROWSER_TEST_F(BraveContentBrowserClientTest,
MagnetIframeWithoutUserGestureDoesNotOpenWebtorrent) {
content::WebContents* contents =
browser()->tab_strip_model()->GetActiveWebContents();
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), magnet_html_url()));
EXPECT_TRUE(content::ExecJs(contents, "createMagnetIframe(false);",
content::EXECUTE_SCRIPT_NO_USER_GESTURE));
// Magnet protocol handler posts to UIThreadTaskRunner, so let all tasks run,
// otherwise WaitForLoadStop may return right away.
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(WaitForLoadStop(contents));
EXPECT_EQ(contents->GetLastCommittedURL(), magnet_html_url());
}
IN_PROC_BROWSER_TEST_F(BraveContentBrowserClientTest,
MagnetIframeSandboxedDoesNotOpenWebtorrent) {
content::WebContents* contents =
browser()->tab_strip_model()->GetActiveWebContents();
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), magnet_html_url()));
EXPECT_TRUE(content::ExecJs(contents, "createMagnetIframe(true);"));
// Magnet protocol handler posts to UIThreadTaskRunner, so let all tasks run,
// otherwise WaitForLoadStop may return right away.
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(WaitForLoadStop(contents));
EXPECT_EQ(contents->GetLastCommittedURL(), magnet_html_url());
}
IN_PROC_BROWSER_TEST_F(BraveContentBrowserClientTest,
NoReverseRewriteTorrentURLForInvalidQuery) {
browser()->profile()->GetPrefs()->SetBoolean(kWebTorrentEnabled, true);
content::WebContents* contents =
browser()->tab_strip_model()->GetActiveWebContents();
// Used to add the extension
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), magnet_url()));
ASSERT_TRUE(WaitForLoadStop(contents));
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(), torrent_invalid_query_extension_url()));
ASSERT_TRUE(WaitForLoadStop(contents));
EXPECT_EQ(contents->GetLastCommittedURL().spec(),
torrent_invalid_query_extension_url().spec())
<< "URL visible to users should stay as extension URL for invalid query";
content::NavigationEntry* entry =
contents->GetController().GetLastCommittedEntry();
EXPECT_EQ(entry->GetURL().spec(),
torrent_invalid_query_extension_url().spec())
<< "Real URL should be extension URL";
}
IN_PROC_BROWSER_TEST_F(BraveContentBrowserClientTest,
WebTorrentExtensionEnabledAfterLoad) {
browser()->profile()->GetPrefs()->SetBoolean(kWebTorrentEnabled, true);
extensions::ExtensionRegistry* registry =
extensions::ExtensionRegistry::Get(browser()->profile());
ASSERT_FALSE(
registry->enabled_extensions().Contains(brave_webtorrent_extension_id));
content::WebContents* contents =
browser()->tab_strip_model()->GetActiveWebContents();
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), magnet_url()));
WaitForLoadStop(contents);
ASSERT_TRUE(
registry->enabled_extensions().Contains(brave_webtorrent_extension_id));
}
IN_PROC_BROWSER_TEST_F(BraveContentBrowserClientTest,
PRE_NoRewriteMagnetURLURLBarWebTorrentDisabled) {
browser()->profile()->GetPrefs()->SetBoolean(kWebTorrentEnabled, false);
}
IN_PROC_BROWSER_TEST_F(BraveContentBrowserClientTest,
NoRewriteMagnetURLURLBarWebTorrentDisabled) {
ASSERT_FALSE(
browser()->profile()->GetPrefs()->GetBoolean(kWebTorrentEnabled));
extensions::ExtensionRegistry* registry =
extensions::ExtensionRegistry::Get(browser()->profile());
ASSERT_FALSE(
registry->enabled_extensions().Contains(brave_webtorrent_extension_id));
content::WebContents* contents =
browser()->tab_strip_model()->GetActiveWebContents();
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), magnet_url()));
ASSERT_TRUE(WaitForLoadStop(contents));
EXPECT_EQ(contents->GetLastCommittedURL().spec(), "about:blank");
content::NavigationEntry* entry =
contents->GetController().GetLastCommittedEntry();
EXPECT_EQ(entry->GetURL().spec(), "about:blank");
}
IN_PROC_BROWSER_TEST_F(BraveContentBrowserClientTest,
PRE_NoRewriteMagnetURLLinkWebTorrentDisabled) {
browser()->profile()->GetPrefs()->SetBoolean(kWebTorrentEnabled, false);
}
IN_PROC_BROWSER_TEST_F(BraveContentBrowserClientTest,
NoRewriteMagnetURLLinkWebTorrentDisabled) {
ASSERT_FALSE(
browser()->profile()->GetPrefs()->GetBoolean(kWebTorrentEnabled));
extensions::ExtensionRegistry* registry =
extensions::ExtensionRegistry::Get(browser()->profile());
ASSERT_FALSE(
registry->enabled_extensions().Contains(brave_webtorrent_extension_id));
content::WebContents* contents =
browser()->tab_strip_model()->GetActiveWebContents();
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), magnet_html_url()));
ASSERT_TRUE(WaitForLoadStop(contents));
EXPECT_TRUE(content::ExecJs(contents, "clickMagnetLink();"));
// Magnet protocol handler posts to UIThreadTaskRunner, so let all tasks run,
// otherwise WaitForLoadStop may return right away.
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(WaitForLoadStop(contents));
EXPECT_EQ(contents->GetLastCommittedURL().spec(), magnet_html_url().spec());
content::NavigationEntry* entry =
contents->GetController().GetLastCommittedEntry();
EXPECT_EQ(entry->GetURL().spec(), magnet_html_url().spec());
}
IN_PROC_BROWSER_TEST_F(BraveContentBrowserClientTest,
PRE_NoReverseRewriteTorrentURLWebTorrentDisabled) {
browser()->profile()->GetPrefs()->SetBoolean(kWebTorrentEnabled, false);
}
IN_PROC_BROWSER_TEST_F(BraveContentBrowserClientTest,
NoReverseRewriteTorrentURLWebTorrentDisabled) {
ASSERT_FALSE(
browser()->profile()->GetPrefs()->GetBoolean(kWebTorrentEnabled));
extensions::ExtensionRegistry* registry =
extensions::ExtensionRegistry::Get(browser()->profile());
ASSERT_FALSE(
registry->enabled_extensions().Contains(brave_webtorrent_extension_id));
content::WebContents* contents =
browser()->tab_strip_model()->GetActiveWebContents();
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), torrent_extension_url()));
WaitForLoadStop(contents);
EXPECT_EQ(contents->GetLastCommittedURL().spec(),
torrent_extension_url().spec())
<< "No changes on the visible URL";
content::NavigationEntry* entry =
contents->GetController().GetLastCommittedEntry();
EXPECT_EQ(entry->GetURL().spec(), torrent_extension_url().spec())
<< "No changes on the real URL";
}
#endif // BUILDFLAG(ENABLE_BRAVE_WEBTORRENT)
#if BUILDFLAG(ENABLE_TOR)
IN_PROC_BROWSER_TEST_F(BraveContentBrowserClientTest, MixedContentForOnion) {
net::ProxyConfigServiceTor::SetBypassTorProxyConfigForTesting(true);
-5
View File
@@ -13,7 +13,6 @@
#include "brave/components/brave_wallet/browser/pref_names.h"
#include "brave/components/brave_wallet/common/brave_wallet.mojom.h"
#include "brave/components/brave_wayback_machine/buildflags/buildflags.h"
#include "brave/components/brave_webtorrent/browser/buildflags/buildflags.h"
#include "brave/components/constants/pref_names.h"
#include "brave/components/ntp_background_images/buildflags/buildflags.h"
#include "build/build_config.h"
@@ -82,10 +81,6 @@ IN_PROC_BROWSER_TEST_F(BraveProfilePrefsBrowserTest, MiscBravePrefs) {
brave_shields::prefs::kReduceLanguageEnabled),
base::FeatureList::IsEnabled(
brave_shields::features::kBraveReduceLanguage));
#if BUILDFLAG(ENABLE_BRAVE_WEBTORRENT)
EXPECT_FALSE(chrome_test_utils::GetProfile(this)->GetPrefs()->GetBoolean(
kWebTorrentEnabled));
#endif
#if BUILDFLAG(ENABLE_BRAVE_WAYBACK_MACHINE)
EXPECT_TRUE(chrome_test_utils::GetProfile(this)->GetPrefs()->GetBoolean(
kBraveWaybackMachineEnabled));
-1
View File
@@ -38,7 +38,6 @@
#include "brave/components/brave_vpn/common/buildflags/buildflags.h"
#include "brave/components/brave_wallet/browser/brave_wallet_prefs.h"
#include "brave/components/brave_wayback_machine/buildflags/buildflags.h"
#include "brave/components/brave_webtorrent/browser/buildflags/buildflags.h"
#include "brave/components/constants/pref_names.h"
#include "brave/components/containers/buildflags/buildflags.h"
#include "brave/components/de_amp/common/pref_names.h"
-17
View File
@@ -5,7 +5,6 @@
import("//brave/components/brave_vpn/common/buildflags/buildflags.gni")
import("//brave/components/brave_wayback_machine/buildflags/buildflags.gni")
import("//brave/components/brave_webtorrent/browser/buildflags/buildflags.gni")
import("//brave/components/playlist/common/buildflags/buildflags.gni")
import("//brave/components/speedreader/common/buildflags/buildflags.gni")
import("//brave/components/tor/buildflags/buildflags.gni")
@@ -26,7 +25,6 @@ source_set("component_loader") {
"//base",
"//brave/components/brave_component_updater/browser",
"//brave/components/brave_extension:static_resources",
"//brave/components/brave_webtorrent:static_resources",
"//chrome/browser:browser_process",
"//chrome/browser/extensions",
"//chrome/browser/profiles:profile",
@@ -126,7 +124,6 @@ source_set("extensions") {
"//brave/components/brave_wallet/browser:utils",
"//brave/components/brave_wallet/common",
"//brave/components/brave_wayback_machine/buildflags",
"//brave/components/brave_webtorrent:static_resources",
"//brave/components/constants",
"//brave/components/de_amp/common",
"//brave/components/debounce/core/common",
@@ -203,14 +200,6 @@ source_set("extensions") {
"//components/prefs",
]
if (enable_brave_webtorrent) {
sources += [
"brave_webtorrent_navigation_throttle.cc",
"brave_webtorrent_navigation_throttle.h",
]
deps += [ "//brave/components/brave_webtorrent/browser" ]
}
allow_circular_includes_from = [ ":brave_prefs_util_impl" ]
}
@@ -219,12 +208,6 @@ group("resources") {
"//brave/components/brave_extension:generated_resources",
"//brave/components/brave_extension:static_resources",
]
if (enable_brave_webtorrent) {
deps += [
"//brave/components/brave_webtorrent:generated_resources",
"//brave/components/brave_webtorrent:static_resources",
]
}
}
source_set("test_support") {
-1
View File
@@ -1,5 +1,4 @@
include_rules = [
"+brave/components/brave_extension/grit",
"+brave/components/brave_webtorrent/grit",
"+brave/components/update_client/buildflags.h",
]
@@ -214,8 +214,6 @@ const PrefsUtil::TypedPrefMap& BravePrefsUtil::GetAllowlistedKeys() {
(*s_brave_allowlist)[kAlwaysShowBookmarkBarOnNTP] =
settings_api::PrefType::kBoolean;
(*s_brave_allowlist)[kMRUCyclingEnabled] = settings_api::PrefType::kBoolean;
// WebTorrent pref
(*s_brave_allowlist)[kWebTorrentEnabled] = settings_api::PrefType::kBoolean;
#if BUILDFLAG(ENABLE_BRAVE_WAYBACK_MACHINE)
(*s_brave_allowlist)[kBraveWaybackMachineEnabled] =
settings_api::PrefType::kBoolean;
@@ -16,7 +16,6 @@
#include "brave/components/brave_component_updater/browser/brave_component_installer.h"
#include "brave/components/brave_component_updater/browser/brave_on_demand_updater.h"
#include "brave/components/brave_extension/grit/brave_extension.h"
#include "brave/components/brave_webtorrent/grit/brave_webtorrent_resources.h"
#include "brave/components/constants/brave_switches.h"
#include "brave/components/constants/pref_names.h"
#include "chrome/browser/browser_process.h"
@@ -83,19 +82,6 @@ void BraveComponentLoader::AddDefaultComponentExtensions(
UpdateBraveExtension();
}
void BraveComponentLoader::AddWebTorrentExtension() {
const base::CommandLine& command_line =
*base::CommandLine::ForCurrentProcess();
if (!command_line.HasSwitch(switches::kDisableWebTorrentExtension) &&
(!profile_prefs_->FindPreference(kWebTorrentEnabled) ||
profile_prefs_->GetBoolean(kWebTorrentEnabled))) {
base::FilePath brave_webtorrent_path(FILE_PATH_LITERAL(""));
brave_webtorrent_path =
brave_webtorrent_path.Append(FILE_PATH_LITERAL("brave_webtorrent"));
Add(IDR_BRAVE_WEBTORRENT, brave_webtorrent_path);
}
}
bool BraveComponentLoader::UseBraveExtensionBackgroundPage() {
// Keep sync with `pref_change_registrar_` in the ctor.
return profile_prefs_->GetBoolean(kWebDiscoveryEnabled);
@@ -33,7 +33,6 @@ class BraveComponentLoader : public ComponentLoader {
void AddDefaultComponentExtensions(bool skip_session_components) override;
void OnComponentRegistered(std::string extension_id);
void AddWebTorrentExtension();
void OnComponentReady(std::string extension_id,
bool allow_file_access,
const base::FilePath& install_dir,
@@ -1,88 +0,0 @@
/* Copyright (c) 2019 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "brave/browser/extensions/brave_webtorrent_navigation_throttle.h"
#include "brave/browser/extensions/brave_component_loader.h"
#include "brave/components/brave_webtorrent/browser/webtorrent_util.h"
#include "brave/components/constants/pref_names.h"
#include "brave/components/constants/url_constants.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/profiles/profile.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/url_constants.h"
#include "extensions/browser/extension_system.h"
#include "extensions/common/constants.h"
#include "extensions/common/extension.h"
namespace extensions {
BraveWebTorrentNavigationThrottle::BraveWebTorrentNavigationThrottle(
content::NavigationHandle* navigation_handle)
: content::NavigationThrottle(navigation_handle) {}
BraveWebTorrentNavigationThrottle::~BraveWebTorrentNavigationThrottle() {}
content::NavigationThrottle::ThrottleCheckResult
BraveWebTorrentNavigationThrottle::WillStartRequest() {
// This handles magnet URLs and .torrent filenames in the URL but not
// response headers.
return CommonWillProcessRequestResponse();
}
content::NavigationThrottle::ThrottleCheckResult
BraveWebTorrentNavigationThrottle::WillProcessResponse() {
// This handles response headers with headers that indicate torrent content.
// This is not as good as if we catch it in the WillStartRequest section
// because the user will need to manually restart the request to make it work.
return CommonWillProcessRequestResponse();
}
// static
bool BraveWebTorrentNavigationThrottle::MaybeLoadWebtorrent(
content::BrowserContext* context,
const GURL& url) {
// No need to load Webtorrent if pref is off or it is already enabled.
auto* prefs = Profile::FromBrowserContext(context)->GetPrefs();
if (!prefs->GetBoolean(kWebTorrentEnabled) ||
webtorrent::IsWebtorrentEnabled(context)) {
return false;
}
static_cast<extensions::BraveComponentLoader*>(
extensions::ComponentLoader::Get(context))
->AddWebTorrentExtension();
return true;
}
content::NavigationThrottle::ThrottleCheckResult
BraveWebTorrentNavigationThrottle::CommonWillProcessRequestResponse() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
content::WebContents* web_contents = navigation_handle()->GetWebContents();
// Is this navigation targeting an extension resource?
const GURL& url = navigation_handle()->GetURL();
// Note, if we use WillProcessResponse we can also use response headers, but
// it would be too late to handle the request as WebTorrent in that case.
// So the best we can do is via URL pattern match and magnet links.
// Headers are null when processing WillStartRequest.
auto* headers = navigation_handle()->GetResponseHeaders();
bool is_torrent_file = headers ? webtorrent::IsTorrentFile(url, headers)
: webtorrent::TorrentURLMatched(url);
if (url.SchemeIs(kMagnetScheme) || is_torrent_file) {
MaybeLoadWebtorrent(web_contents->GetBrowserContext(), url);
}
return content::NavigationThrottle::PROCEED;
}
const char* BraveWebTorrentNavigationThrottle::GetNameForLogging() {
return "BraveWebTorrentNavigationThrottle";
}
} // namespace extensions
@@ -1,47 +0,0 @@
/* Copyright (c) 2019 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef BRAVE_BROWSER_EXTENSIONS_BRAVE_WEBTORRENT_NAVIGATION_THROTTLE_H_
#define BRAVE_BROWSER_EXTENSIONS_BRAVE_WEBTORRENT_NAVIGATION_THROTTLE_H_
#include "base/scoped_observation.h"
#include "base/timer/timer.h"
#include "content/public/browser/navigation_throttle.h"
#include "url/gurl.h"
namespace content {
class BrowserContext;
class NavigationHandle;
}
namespace extensions {
// This class enables the WebTorrent component when a .torrent
// or magnet file is loaded.
class BraveWebTorrentNavigationThrottle : public content::NavigationThrottle {
public:
explicit BraveWebTorrentNavigationThrottle(
content::NavigationHandle* navigation_handle);
BraveWebTorrentNavigationThrottle(const BraveWebTorrentNavigationThrottle&) =
delete;
BraveWebTorrentNavigationThrottle& operator=(
const BraveWebTorrentNavigationThrottle&) = delete;
~BraveWebTorrentNavigationThrottle() override;
// content::NavigationThrottle implementation:
ThrottleCheckResult WillStartRequest() override;
ThrottleCheckResult WillProcessResponse() override;
const char* GetNameForLogging() override;
static bool MaybeLoadWebtorrent(
content::BrowserContext* context, const GURL& url);
private:
ThrottleCheckResult CommonWillProcessRequestResponse();
};
} // namespace extensions
#endif // BRAVE_BROWSER_EXTENSIONS_BRAVE_WEBTORRENT_NAVIGATION_THROTTLE_H_
@@ -1,237 +0,0 @@
/* Copyright (c) 2019 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "brave/browser/extensions/brave_webtorrent_navigation_throttle.h"
#include <memory>
#include <utility>
#include <vector>
#include "base/command_line.h"
#include "base/files/scoped_temp_dir.h"
#include "base/memory/raw_ptr.h"
#include "base/values.h"
#include "brave/components/constants/pref_names.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/load_error_reporter.h"
#include "chrome/browser/extensions/test_extension_system.h"
#include "chrome/browser/prefs/browser_prefs.h"
#include "chrome/test/base/scoped_testing_local_state.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_profile.h"
#include "components/prefs/testing_pref_service.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/navigation_throttle_registry.h"
#include "content/public/common/content_client.h"
#include "content/public/test/mock_navigation_handle.h"
#include "content/public/test/test_renderer_host.h"
#include "content/public/test/web_contents_tester.h"
#include "extensions/browser/extension_system.h"
#include "extensions/common/constants.h"
#include "extensions/common/extension.h"
#include "extensions/common/extension_builder.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
using content::NavigationThrottle;
namespace extensions {
namespace {
class MockBrowserClient : public content::ContentBrowserClient {
public:
MockBrowserClient() = default;
~MockBrowserClient() override = default;
// Only construct an BraveWebTorrentNavigationThrottle so that we can test it
// in isolation.
void CreateThrottlesForNavigation(
content::NavigationThrottleRegistry& registry) override {
registry.AddThrottle(std::make_unique<BraveWebTorrentNavigationThrottle>(
&registry.GetNavigationHandle()));
}
};
const GURL& GetMagnetUrl() {
static const GURL magnet_url(
"magnet:?xt=urn:btih:dd8255ecdc7ca55fb0bbf81323d87062db1f6d1c&dn=Big+Buck+Bunny&tr=udp%3A%2F%2Fexplodie.org%3A6969&tr=udp%3A%2F%2Ftracker.coppersurfer.tk%3A6969&tr=udp%3A%2F%2Ftracker.empire-js.us%3A1337&tr=udp%3A%2F%2Ftracker.leechers-paradise.org%3A6969&tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337&tr=wss%3A%2F%2Ftracker.btorrent.xyz&tr=wss%3A%2F%2Ftracker.fastcast.nz&tr=wss%3A%2F%2Ftracker.openwebtorrent.com&ws=https%3A%2F%2Fwebtorrent.io%2Ftorrents%2F&xs=https%3A%2F%2Fwebtorrent.io%2Ftorrents%2Fbig-buck-bunny.torrent"); // NOLINT
return magnet_url;
}
const GURL& GetTorrentUrl() {
static const GURL torrent_url(
"https://webtorrent.io/torrents/big-buck-bunny.torrent");
return torrent_url;
}
} // namespace
class BraveWebTorrentNavigationThrottleUnitTest
: public content::RenderViewHostTestHarness {
public:
BraveWebTorrentNavigationThrottleUnitTest()
: local_state_(TestingBrowserProcess::GetGlobal()) {
}
BraveWebTorrentNavigationThrottleUnitTest(
const BraveWebTorrentNavigationThrottleUnitTest&) = delete;
BraveWebTorrentNavigationThrottleUnitTest& operator=(
const BraveWebTorrentNavigationThrottleUnitTest&) = delete;
void SetUp() override {
original_client_ = content::SetBrowserClientForTesting(&client_);
content::RenderViewHostTestHarness::SetUp();
// Initialize the various pieces of the extensions system.
extensions::LoadErrorReporter::Init(false);
extensions::TestExtensionSystem* extension_system =
static_cast<extensions::TestExtensionSystem*>(
extensions::ExtensionSystem::Get(profile()));
extension_system->CreateExtensionService(
base::CommandLine::ForCurrentProcess(), base::FilePath(), false);
extension_service_ =
extensions::ExtensionSystem::Get(profile())->extension_service();
}
std::unique_ptr<content::BrowserContext> CreateBrowserContext() override {
TestingProfile::Builder builder;
auto prefs =
std::make_unique<sync_preferences::TestingPrefServiceSyncable>();
RegisterUserProfilePrefs(prefs->registry());
builder.SetPrefService(std::move(prefs));
return builder.Build();
}
void TearDown() override {
extension_service_ = nullptr;
content::SetBrowserClientForTesting(original_client_);
content::RenderViewHostTestHarness::TearDown();
}
extensions::ExtensionService* extension_service() {
return extension_service_;
}
content::RenderFrameHostTester* render_frame_host_tester(
content::RenderFrameHost* host) {
return content::RenderFrameHostTester::For(host);
}
content::WebContentsTester* web_contents_tester() {
return content::WebContentsTester::For(web_contents());
}
TestingProfile* profile() {
return static_cast<TestingProfile*>(browser_context());
}
void AddExtension() {
extension_ = ExtensionBuilder()
.SetManifest(base::Value::Dict()
.Set("name", "ext")
.Set("version", "0.1")
.Set("manifest_version", 2))
.SetID(brave_webtorrent_extension_id)
.Build();
ASSERT_TRUE(extension_);
ExtensionRegistrar::Get(profile())->AddExtension(extension_);
}
private:
scoped_refptr<const Extension> extension_;
MockBrowserClient client_;
ScopedTestingLocalState local_state_;
base::ScopedTempDir temp_dir_;
sync_preferences::TestingPrefServiceSyncable prefs_;
raw_ptr<content::ContentBrowserClient> original_client_ = nullptr;
// The ExtensionService associated with the primary profile.
raw_ptr<extensions::ExtensionService> extension_service_ = nullptr;
};
// Tests the basic case of loading a URL, it should proceed.
TEST_F(BraveWebTorrentNavigationThrottleUnitTest, ExternalWebPage) {
web_contents_tester()->NavigateAndCommit(GURL("http://example.com"));
content::RenderFrameHost* host =
render_frame_host_tester(main_rfh())->AppendChild("child");
GURL url("http://www.example.com");
content::MockNavigationHandle test_handle(url, host);
test_handle.set_starting_site_instance(host->GetSiteInstance());
auto throttle =
std::make_unique<BraveWebTorrentNavigationThrottle>(&test_handle);
EXPECT_EQ(NavigationThrottle::PROCEED, throttle->WillStartRequest().action())
<< url;
}
// Tests the case of loading a torrent without having the extension installed.
// It should proceed with the navigation (it used to defer prior to changes in
// cr114, but OnExtensionReady is triggered immediately now when loading the
// WebTorrent extension).
TEST_F(BraveWebTorrentNavigationThrottleUnitTest,
WebTorrentUrlNotInstalled) {
web_contents_tester()->NavigateAndCommit(GURL("http://example.com"));
content::RenderFrameHost* host =
render_frame_host_tester(main_rfh())->AppendChild("child");
content::MockNavigationHandle test_handle(GetTorrentUrl(), host);
test_handle.set_starting_site_instance(host->GetSiteInstance());
auto throttle =
std::make_unique<BraveWebTorrentNavigationThrottle>(&test_handle);
EXPECT_EQ(NavigationThrottle::PROCEED, throttle->WillStartRequest().action())
<< GetTorrentUrl();
}
// Tests the case of loading a torrent without having the extension installed.
// It should proceed with the navigation (it used to defer prior to changes in
// cr114, but OnExtensionReady is triggered immediately now when loading the
// WebTorrent extension).
TEST_F(BraveWebTorrentNavigationThrottleUnitTest,
WebTorrentMagnetUrlNotInstalled) {
web_contents_tester()->NavigateAndCommit(GURL("http://example.com"));
content::RenderFrameHost* host =
render_frame_host_tester(main_rfh())->AppendChild("child");
content::MockNavigationHandle test_handle(GetMagnetUrl(), host);
test_handle.set_starting_site_instance(host->GetSiteInstance());
auto throttle =
std::make_unique<BraveWebTorrentNavigationThrottle>(&test_handle);
EXPECT_EQ(NavigationThrottle::PROCEED, throttle->WillStartRequest().action())
<< GetMagnetUrl();
}
// Tests the case of loading a torrent with the extension installed.
// It should just proceed.
TEST_F(BraveWebTorrentNavigationThrottleUnitTest, WebTorrentUrlInstalled) {
AddExtension();
web_contents_tester()->NavigateAndCommit(GURL("http://example.com"));
content::RenderFrameHost* host =
render_frame_host_tester(main_rfh())->AppendChild("child");
content::MockNavigationHandle test_handle(GetMagnetUrl(), host);
test_handle.set_starting_site_instance(host->GetSiteInstance());
auto throttle =
std::make_unique<BraveWebTorrentNavigationThrottle>(&test_handle);
EXPECT_EQ(NavigationThrottle::PROCEED, throttle->WillStartRequest().action())
<< GetMagnetUrl();
}
// Tests the case of loading a torrent when the WebTorrent is explicitly
// disabled.
TEST_F(BraveWebTorrentNavigationThrottleUnitTest, WebTorrentDisabledByPref) {
profile()->GetPrefs()->SetBoolean(kWebTorrentEnabled, false);
web_contents_tester()->NavigateAndCommit(GURL("http://example.com"));
content::RenderFrameHost* host =
render_frame_host_tester(main_rfh())->AppendChild("child");
content::MockNavigationHandle test_handle(GetMagnetUrl(), host);
test_handle.set_starting_site_instance(host->GetSiteInstance());
auto throttle =
std::make_unique<BraveWebTorrentNavigationThrottle>(&test_handle);
EXPECT_EQ(NavigationThrottle::PROCEED,
throttle->WillStartRequest().action()) << GetMagnetUrl();
}
} // namespace extensions
-1
View File
@@ -6,5 +6,4 @@
brave_extensions_resources = [
"//brave/browser/extensions/api:generated_api_registration",
"//brave/browser/extensions:resources",
"//brave/components/brave_webtorrent/browser/buildflags",
]
-13
View File
@@ -3,7 +3,6 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at https://mozilla.org/MPL/2.0/.
import("//brave/components/brave_webtorrent/browser/buildflags/buildflags.gni")
import("//brave/components/tor/buildflags/buildflags.gni")
import("//build/config/features.gni")
@@ -91,16 +90,4 @@ source_set("unit_tests") {
"//testing/gtest",
"//third_party/abseil-cpp:absl",
]
if (enable_brave_webtorrent) {
sources += [
"//brave/browser/extensions/brave_webtorrent_navigation_throttle_unittest.cc",
"//brave/browser/net/brave_torrent_redirect_network_delegate_helper_unittest.cc",
]
deps += [
"//brave/browser/extensions",
"//brave/components/brave_referrals/browser",
]
}
}
+1 -11
View File
@@ -22,7 +22,6 @@
#include "brave/browser/net/global_privacy_control_network_delegate_helper.h"
#include "brave/browser/net/search_ads_header_network_delegate_helper.h"
#include "brave/components/brave_shields/core/common/features.h"
#include "brave/components/brave_webtorrent/browser/buildflags/buildflags.h"
#include "brave/components/constants/pref_names.h"
#include "chrome/browser/browser_process.h"
#include "content/public/browser/browser_task_traits.h"
@@ -34,10 +33,6 @@
#include "net/base/net_errors.h"
#include "third_party/blink/public/common/features.h"
#if BUILDFLAG(ENABLE_BRAVE_WEBTORRENT)
#include "brave/browser/net/brave_torrent_redirect_network_delegate_helper.h"
#endif
static bool IsInternalScheme(std::shared_ptr<brave::BraveRequestInfo> ctx) {
DCHECK(ctx);
#if BUILDFLAG(ENABLE_EXTENSIONS)
@@ -103,12 +98,6 @@ void BraveRequestHandler::SetupCallbacks() {
base::BindRepeating(brave::OnBeforeStartTransaction_SearchAdsHeader);
before_start_transaction_callbacks_.push_back(start_transaction_callback);
#if BUILDFLAG(ENABLE_BRAVE_WEBTORRENT)
brave::OnHeadersReceivedCallback headers_received_callback =
base::BindRepeating(webtorrent::OnHeadersReceived_TorrentRedirectWork);
headers_received_callbacks_.push_back(headers_received_callback);
#endif
if (base::FeatureList::IsEnabled(
::brave_shields::features::kBraveAdblockCspRules)) {
brave::OnHeadersReceivedCallback headers_received_callback2 =
@@ -164,6 +153,7 @@ int BraveRequestHandler::OnHeadersReceived(
if (headers_received_callbacks_.empty() &&
!ctx->request_url.SchemeIs(content::kChromeUIScheme)) {
// TODO(bsclifton): can this be removed?
// Extension scheme not excluded since brave_webtorrent needs it.
return net::OK;
}
@@ -1,94 +0,0 @@
/* Copyright (c) 2019 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "brave/browser/net/brave_torrent_redirect_network_delegate_helper.h"
#include <memory>
#include <string>
#include "base/strings/strcat.h"
#include "base/strings/string_util.h"
#include "brave/components/brave_webtorrent/browser/webtorrent_util.h"
#include "brave/components/constants/network_constants.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/site_instance.h"
#include "content/public/browser/web_contents.h"
#include "extensions/common/constants.h"
#include "net/http/http_content_disposition.h"
#include "net/http/http_response_headers.h"
#include "net/url_request/url_request.h"
#include "third_party/blink/public/mojom/loader/resource_load_info.mojom-shared.h"
#include "ui/base/page_transition_types.h"
#include "url/origin.h"
namespace {
// Returns true if the URL contains a URL fragment that starts with "ix=". For
// example, https://webtorrent.io/torrents/big-buck-bunny.torrent#ix=1.
bool IsViewerURL(const GURL& url) {
return base::StartsWith(url.ref(),
"ix=", base::CompareCase::INSENSITIVE_ASCII);
}
bool IsWebtorrentInitiated(std::shared_ptr<brave::BraveRequestInfo> ctx) {
return ctx->initiator_url.scheme() == extensions::kExtensionScheme &&
ctx->initiator_url.host() == brave_webtorrent_extension_id;
}
// Returns true if the resource type is a frame (i.e. a top level page) or a
// subframe (i.e. a frame or iframe). For all other resource types (stylesheet,
// script, XHR request, etc.), returns false.
bool IsMainFrameResource(std::shared_ptr<brave::BraveRequestInfo> ctx) {
return ctx->resource_type == blink::mojom::ResourceType::kMainFrame;
}
} // namespace
namespace webtorrent {
bool ShouldRedirectRequest(
const net::HttpResponseHeaders* original_response_headers,
std::shared_ptr<brave::BraveRequestInfo> ctx) {
return !(!original_response_headers || !IsMainFrameResource(ctx) ||
ctx->is_webtorrent_disabled ||
// download .torrent, do not redirect
(IsWebtorrentInitiated(ctx) && !IsViewerURL(ctx->request_url)) ||
!IsTorrentFile(ctx->request_url, original_response_headers));
}
int OnHeadersReceived_TorrentRedirectWork(
const net::HttpResponseHeaders* original_response_headers,
scoped_refptr<net::HttpResponseHeaders>* override_response_headers,
GURL* allowed_unsafe_redirect_url,
const brave::ResponseCallback& next_callback,
std::shared_ptr<brave::BraveRequestInfo> ctx) {
if (!ShouldRedirectRequest(original_response_headers, ctx)) {
return net::OK;
}
auto* contents =
content::WebContents::FromFrameTreeNodeId(ctx->frame_tree_node_id);
if (!contents) {
return net::OK;
}
// We don't allow websites to directly link to the WebTorrent extension.
// However, this means that we can't simply redirect here (as that would be
// blocked), and instead, we need to create a new navigation.
GURL url(base::StrCat(
{extensions::kExtensionScheme, "://", brave_webtorrent_extension_id,
"/extension/brave_webtorrent2.html?", ctx->request_url.spec()}));
content::NavigationController::LoadURLParams params(url);
params.initiator_origin = url::Origin::Create(url);
params.source_site_instance = content::SiteInstance::CreateForURL(
contents->GetBrowserContext(), params.initiator_origin->GetURL());
params.transition_type = ui::PAGE_TRANSITION_FROM_API;
contents->GetController().LoadURLWithParams(params);
return net::OK;
}
} // namespace webtorrent
@@ -1,43 +0,0 @@
/* Copyright (c) 2019 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef BRAVE_BROWSER_NET_BRAVE_TORRENT_REDIRECT_NETWORK_DELEGATE_HELPER_H_
#define BRAVE_BROWSER_NET_BRAVE_TORRENT_REDIRECT_NETWORK_DELEGATE_HELPER_H_
#include <memory>
#include "brave/browser/net/url_context.h"
namespace brave {
struct BraveRequestInfo;
}
namespace net {
class URLRequest;
}
namespace webtorrent {
// Determines whether a request should be redirected to a torrent file. This
// will occur if the following conditions are met:
// 1. The request succeeded
// 2. The request is in the Main frame
// 3. WebTorrent is enabled
// 4. The request is for a torrent file / or the WebTorrent extension initiated
// the request.
bool ShouldRedirectRequest(
const net::HttpResponseHeaders* original_response_headers,
std::shared_ptr<brave::BraveRequestInfo> ctx);
int OnHeadersReceived_TorrentRedirectWork(
const net::HttpResponseHeaders* original_response_headers,
scoped_refptr<net::HttpResponseHeaders>* override_response_headers,
GURL* allowed_unsafe_redirect_url,
const brave::ResponseCallback& next_callback,
std::shared_ptr<brave::BraveRequestInfo> ctx);
} // namespace webtorrent
#endif // BRAVE_BROWSER_NET_BRAVE_TORRENT_REDIRECT_NETWORK_DELEGATE_HELPER_H_
@@ -1,248 +0,0 @@
// Copyright (c) 2019 The Brave Authors. All rights reserved.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
#include "brave/browser/net/brave_torrent_redirect_network_delegate_helper.h"
#include <memory>
#include <string>
#include "base/strings/strcat.h"
#include "brave/browser/net/url_context.h"
#include "brave/components/constants/network_constants.h"
#include "net/base/net_errors.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/mojom/loader/resource_load_info.mojom-shared.h"
using brave::ResponseCallback;
class BraveTorrentRedirectNetworkDelegateHelperTest : public testing::Test {
public:
BraveTorrentRedirectNetworkDelegateHelperTest() {
torrent_url_ = GURL("https://webtorrent.io/torrents/sintel.torrent");
torrent_viewer_url_ =
GURL("https://webtorrent.io/torrents/sintel.torrent#ix=0");
non_torrent_url_ = GURL("https://webtorrent.io/torrents/sintel");
torrent_extension_url_ = GURL(
"chrome-extension://lgjmpdmojkpocjcopdikifhejkkjglho/extension/"
"brave_webtorrent2.html?https://webtorrent.io/torrents/sintel.torrent");
torrent_viewer_extension_url_ = GURL(
"chrome-extension://lgjmpdmojkpocjcopdikifhejkkjglho/extension/"
"brave_webtorrent2.html?https://webtorrent.io/torrents/sintel.torrent"
"#ix=0");
non_torrent_extension_url_ = GURL(
"chrome-extension://lgjmpdmojkpocjcopdikifhejkkjglho/extension/"
"brave_webtorrent2.html?https://webtorrent.io/torrents/sintel");
}
const GURL& torrent_url() { return torrent_url_; }
const GURL& torrent_viewer_url() { return torrent_viewer_url_; }
const GURL& non_torrent_url() { return non_torrent_url_; }
const GURL& torrent_extension_url() { return torrent_extension_url_; }
const GURL& torrent_viewer_extension_url() {
return torrent_viewer_extension_url_;
}
const GURL& non_torrent_extension_url() { return non_torrent_extension_url_; }
private:
GURL torrent_url_;
GURL torrent_viewer_url_;
GURL non_torrent_url_;
GURL torrent_extension_url_;
GURL torrent_viewer_extension_url_;
GURL non_torrent_extension_url_;
};
TEST_F(BraveTorrentRedirectNetworkDelegateHelperTest,
NoRedirectWithoutMimeType) {
scoped_refptr<net::HttpResponseHeaders> orig_response_headers =
new net::HttpResponseHeaders(std::string());
scoped_refptr<net::HttpResponseHeaders> overwrite_response_headers =
new net::HttpResponseHeaders(std::string());
GURL allowed_unsafe_redirect_url;
auto request_info = std::make_shared<brave::BraveRequestInfo>(torrent_url());
request_info->resource_type = blink::mojom::ResourceType::kMainFrame;
int rc = webtorrent::OnHeadersReceived_TorrentRedirectWork(
orig_response_headers.get(), &overwrite_response_headers,
&allowed_unsafe_redirect_url, ResponseCallback(), request_info);
EXPECT_EQ(overwrite_response_headers->GetStatusLine(), "HTTP/1.0 200 OK");
std::string location;
EXPECT_FALSE(overwrite_response_headers->EnumerateHeader(nullptr, "Location",
&location));
EXPECT_EQ(allowed_unsafe_redirect_url, GURL());
EXPECT_EQ(rc, net::OK);
}
TEST_F(BraveTorrentRedirectNetworkDelegateHelperTest,
BittorrentMimeTypeRedirect) {
scoped_refptr<net::HttpResponseHeaders> orig_response_headers =
new net::HttpResponseHeaders(std::string());
orig_response_headers->AddHeader("Content-Type", kBittorrentMimeType);
std::string mime_type;
ASSERT_TRUE(orig_response_headers->GetMimeType(&mime_type));
ASSERT_EQ(mime_type, kBittorrentMimeType);
scoped_refptr<net::HttpResponseHeaders> overwrite_response_headers =
new net::HttpResponseHeaders(std::string());
GURL allowed_unsafe_redirect_url;
auto request_info = std::make_shared<brave::BraveRequestInfo>(torrent_url());
request_info->resource_type = blink::mojom::ResourceType::kMainFrame;
auto will_redirect = webtorrent::ShouldRedirectRequest(
orig_response_headers.get(), request_info);
EXPECT_TRUE(will_redirect);
}
TEST_F(BraveTorrentRedirectNetworkDelegateHelperTest,
OctetStreamMimeTypeRedirectWithTorrentURL) {
scoped_refptr<net::HttpResponseHeaders> orig_response_headers =
new net::HttpResponseHeaders(std::string());
orig_response_headers->AddHeader("Content-Type", kOctetStreamMimeType);
std::string mimeType;
ASSERT_TRUE(orig_response_headers->GetMimeType(&mimeType));
ASSERT_EQ(mimeType, kOctetStreamMimeType);
scoped_refptr<net::HttpResponseHeaders> overwrite_response_headers =
new net::HttpResponseHeaders(std::string());
GURL allowed_unsafe_redirect_url;
auto request_info = std::make_shared<brave::BraveRequestInfo>(torrent_url());
request_info->resource_type = blink::mojom::ResourceType::kMainFrame;
auto will_redirect = webtorrent::ShouldRedirectRequest(
orig_response_headers.get(), request_info);
EXPECT_TRUE(will_redirect);
}
TEST_F(BraveTorrentRedirectNetworkDelegateHelperTest,
OctetStreamMimeTypeRedirectWithTorrentFileName) {
scoped_refptr<net::HttpResponseHeaders> orig_response_headers =
new net::HttpResponseHeaders(std::string());
orig_response_headers->AddHeader("Content-Type", kOctetStreamMimeType);
std::string mimeType;
ASSERT_TRUE(orig_response_headers->GetMimeType(&mimeType));
ASSERT_EQ(mimeType, kOctetStreamMimeType);
orig_response_headers->AddHeader("Content-Disposition",
"filename=\"sintel.torrent\"");
ASSERT_TRUE(orig_response_headers->GetNormalizedHeader("Content-Disposition")
.has_value());
scoped_refptr<net::HttpResponseHeaders> overwrite_response_headers =
new net::HttpResponseHeaders(std::string());
GURL allowed_unsafe_redirect_url;
auto request_info =
std::make_shared<brave::BraveRequestInfo>(non_torrent_url());
request_info->resource_type = blink::mojom::ResourceType::kMainFrame;
auto will_redirect = webtorrent::ShouldRedirectRequest(
orig_response_headers.get(), request_info);
EXPECT_TRUE(will_redirect);
}
TEST_F(BraveTorrentRedirectNetworkDelegateHelperTest,
OctetStreamMimeTypeNoRedirect) {
scoped_refptr<net::HttpResponseHeaders> orig_response_headers =
new net::HttpResponseHeaders(std::string());
orig_response_headers->AddHeader("Content-Type", kOctetStreamMimeType);
std::string mime_type;
ASSERT_TRUE(orig_response_headers->GetMimeType(&mime_type));
ASSERT_EQ(mime_type, kOctetStreamMimeType);
scoped_refptr<net::HttpResponseHeaders> overwrite_response_headers =
new net::HttpResponseHeaders(std::string());
GURL allowed_unsafe_redirect_url;
auto request_info =
std::make_shared<brave::BraveRequestInfo>(non_torrent_url());
request_info->resource_type = blink::mojom::ResourceType::kMainFrame;
EXPECT_FALSE(webtorrent::ShouldRedirectRequest(orig_response_headers.get(),
request_info));
}
TEST_F(BraveTorrentRedirectNetworkDelegateHelperTest, MimeTypeNoRedirect) {
scoped_refptr<net::HttpResponseHeaders> orig_response_headers =
new net::HttpResponseHeaders(std::string());
orig_response_headers->AddHeader("Content-Type", "text/html");
std::string mime_type;
ASSERT_TRUE(orig_response_headers->GetMimeType(&mime_type));
ASSERT_EQ(mime_type, "text/html");
scoped_refptr<net::HttpResponseHeaders> overwrite_response_headers =
new net::HttpResponseHeaders(std::string());
GURL allowed_unsafe_redirect_url;
auto request_info = std::make_shared<brave::BraveRequestInfo>(torrent_url());
request_info->resource_type = blink::mojom::ResourceType::kMainFrame;
EXPECT_FALSE(webtorrent::ShouldRedirectRequest(orig_response_headers.get(),
request_info));
}
TEST_F(BraveTorrentRedirectNetworkDelegateHelperTest,
WebtorrentInitiatedNoRedirect) {
scoped_refptr<net::HttpResponseHeaders> orig_response_headers =
new net::HttpResponseHeaders(std::string());
orig_response_headers->AddHeader("Content-Type", kBittorrentMimeType);
std::string mime_type;
ASSERT_TRUE(orig_response_headers->GetMimeType(&mime_type));
ASSERT_EQ(mime_type, kBittorrentMimeType);
scoped_refptr<net::HttpResponseHeaders> overwrite_response_headers =
new net::HttpResponseHeaders(std::string());
GURL allowed_unsafe_redirect_url;
auto request_info = std::make_shared<brave::BraveRequestInfo>(torrent_url());
request_info->initiator_url = torrent_extension_url();
request_info->resource_type = blink::mojom::ResourceType::kMainFrame;
EXPECT_FALSE(webtorrent::ShouldRedirectRequest(orig_response_headers.get(),
request_info));
}
TEST_F(BraveTorrentRedirectNetworkDelegateHelperTest,
WebtorrentInitiatedViewerURLRedirect) {
scoped_refptr<net::HttpResponseHeaders> orig_response_headers =
new net::HttpResponseHeaders(std::string());
orig_response_headers->AddHeader("Content-Type", kBittorrentMimeType);
std::string mime_type;
ASSERT_TRUE(orig_response_headers->GetMimeType(&mime_type));
ASSERT_EQ(mime_type, kBittorrentMimeType);
scoped_refptr<net::HttpResponseHeaders> overwrite_response_headers =
new net::HttpResponseHeaders(std::string());
GURL allowed_unsafe_redirect_url;
auto request_info =
std::make_shared<brave::BraveRequestInfo>(torrent_viewer_url());
request_info->initiator_url = torrent_extension_url();
request_info->resource_type = blink::mojom::ResourceType::kMainFrame;
auto will_redirect = webtorrent::ShouldRedirectRequest(
orig_response_headers.get(), request_info);
EXPECT_TRUE(will_redirect);
}
TEST_F(BraveTorrentRedirectNetworkDelegateHelperTest,
BittorrentNonMainFrameResourceNoRedirect) {
scoped_refptr<net::HttpResponseHeaders> orig_response_headers =
new net::HttpResponseHeaders(std::string());
orig_response_headers->AddHeader("Content-Type", kBittorrentMimeType);
std::string mime_type;
ASSERT_TRUE(orig_response_headers->GetMimeType(&mime_type));
ASSERT_EQ(mime_type, kBittorrentMimeType);
scoped_refptr<net::HttpResponseHeaders> overwrite_response_headers =
new net::HttpResponseHeaders(std::string());
GURL allowed_unsafe_redirect_url;
auto request_info = std::make_shared<brave::BraveRequestInfo>(torrent_url());
request_info->resource_type = blink::mojom::ResourceType::kXhr;
EXPECT_FALSE(webtorrent::ShouldRedirectRequest(orig_response_headers.get(),
request_info));
}
-14
View File
@@ -3,7 +3,6 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at https://mozilla.org/MPL/2.0/.
import("//brave/components/brave_webtorrent/browser/buildflags/buildflags.gni")
import("//brave/components/tor/buildflags/buildflags.gni")
import("//build/config/features.gni")
import("//extensions/buildflags/buildflags.gni")
@@ -70,7 +69,6 @@ brave_browser_net_deps = [
"//brave/components/brave_wallet/browser",
"//brave/components/brave_wallet/common",
"//brave/components/brave_wallet/common:mojom",
"//brave/components/brave_webtorrent/browser/buildflags",
"//brave/components/constants",
"//brave/components/constants:brave_service_key_helper",
"//brave/components/decentralized_dns/content",
@@ -108,15 +106,3 @@ brave_browser_net_deps = [
if (enable_extensions) {
brave_browser_net_deps += [ "//extensions/common:common_constants" ]
}
if (enable_brave_webtorrent) {
brave_browser_net_sources += [
"//brave/browser/net/brave_torrent_redirect_network_delegate_helper.cc",
"//brave/browser/net/brave_torrent_redirect_network_delegate_helper.h",
]
brave_browser_net_deps += [
"//brave/components/brave_webtorrent/browser/",
"//extensions/browser",
]
}
-3
View File
@@ -10,7 +10,6 @@
#include "brave/browser/brave_shields/brave_shields_web_contents_observer.h"
#include "brave/components/brave_shields/content/browser/brave_shields_util.h"
#include "brave/components/brave_webtorrent/browser/buildflags/buildflags.h"
#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "content/public/browser/browser_thread.h"
@@ -70,8 +69,6 @@ std::shared_ptr<brave::BraveRequestInfo> BraveRequestInfo::MakeCTX(
ctx->resource_type =
static_cast<blink::mojom::ResourceType>(request.resource_type);
ctx->is_webtorrent_disabled = true;
ctx->frame_tree_node_id = frame_tree_node_id;
// TODO(iefremov): remove tab_url. Change tab_origin from GURL to Origin.
-1
View File
@@ -86,7 +86,6 @@ struct BraveRequestInfo {
bool aggressive_blocking = false;
bool allow_http_upgradable_resource = false;
bool allow_referrers = false;
bool is_webtorrent_disabled = false;
content::FrameTreeNodeId frame_tree_node_id;
uint64_t request_identifier = 0;
size_t next_url_request_index = 0;
-1
View File
@@ -14,7 +14,6 @@ source_set("util") {
"//brave/common",
"//brave/components/brave_shields/content/browser",
"//brave/components/brave_shields/core/common",
"//brave/components/brave_webtorrent/browser/buildflags",
"//brave/components/ntp_background_images/browser",
"//brave/components/ntp_background_images/common",
"//brave/components/tor/buildflags",
@@ -20,7 +20,6 @@
#include "brave/browser/url_sanitizer/url_sanitizer_service_factory.h"
#include "brave/components/brave_shields/content/browser/brave_shields_p3a.h"
#include "brave/components/brave_shields/content/browser/brave_shields_util.h"
#include "brave/components/brave_webtorrent/browser/buildflags/buildflags.h"
#include "brave/components/constants/pref_names.h"
#include "brave/components/content_settings/core/browser/brave_content_settings_pref_provider.h"
#include "brave/components/ntp_background_images/browser/ntp_p3a_util.h"
@@ -136,9 +135,6 @@ void BraveProfileManager::InitProfileUserPrefs(Profile* profile) {
ProfileManager::InitProfileUserPrefs(profile);
RecordInitialP3AValues(profile);
brave::SetDefaultSearchVersion(profile, profile->IsNewProfile());
#if BUILDFLAG(ENABLE_BRAVE_WEBTORRENT)
brave::SetWebTorrentEnabled(profile, profile->IsNewProfile());
#endif
brave::SetDefaultThirdPartyCookieBlockValue(profile);
perf::MaybeEnableBraveFeatureForPerfTesting(profile);
MigrateHttpsUpgradeSettings(profile);
-13
View File
@@ -35,17 +35,4 @@ void SetDefaultThirdPartyCookieBlockValue(Profile* profile) {
content_settings::CookieControlsMode::kBlockThirdParty)));
}
#if BUILDFLAG(ENABLE_BRAVE_WEBTORRENT)
void SetWebTorrentEnabled(Profile* profile, bool is_new_profile) {
const PrefService::Preference* pref_webtorrent_enabled =
profile->GetPrefs()->FindPreference(kWebTorrentEnabled);
if (!pref_webtorrent_enabled->HasUserSetting()) {
profile->GetPrefs()->SetBoolean(
kWebTorrentEnabled,
is_new_profile ? false
: profile->GetPrefs()->GetBoolean(kWebTorrentEnabled));
}
}
#endif
} // namespace brave
-11
View File
@@ -6,8 +6,6 @@
#ifndef BRAVE_BROWSER_PROFILES_PROFILE_UTIL_H_
#define BRAVE_BROWSER_PROFILES_PROFILE_UTIL_H_
#include "brave/components/brave_webtorrent/browser/buildflags/buildflags.h"
class Profile;
namespace brave {
@@ -22,15 +20,6 @@ void SetDefaultSearchVersion(Profile* profile, bool is_new_profile);
// instead of 'Block Third Party in Incognito'
void SetDefaultThirdPartyCookieBlockValue(Profile* profile);
#if BUILDFLAG(ENABLE_BRAVE_WEBTORRENT)
// Used for capturing the current value of WebTorrent.
// WebTorrent will be disabled for new users starting with
// https://github.com/brave/brave-browser/issues/44303
// Once the feature is deprecated, this code can be removed and the preference
// can be added under `RegisterProfilePrefsForMigration`.
void SetWebTorrentEnabled(Profile* profile, bool is_new_profile);
#endif
// Checks if the user previously had fingerprinting mode disabled.
// If so, set the new fingerprinting toggle to disabled.
void MigrateFingerprintingSettings(Profile* profile);
-42
View File
@@ -82,45 +82,3 @@ TEST_F(BraveProfileUtilTest,
brave::SetDefaultSearchVersion(GetProfile(), true);
ASSERT_EQ(GetPrefs()->GetInteger(prefs::kBraveDefaultSearchVersion), 1);
}
// SetWebTorrentEnabled
// ####################
#if BUILDFLAG(ENABLE_BRAVE_WEBTORRENT)
// No entry yet. Check initialized value
TEST_F(BraveProfileUtilTest, SetWebTorrentEnabledExistingProfileNoEntryYet) {
const PrefService::Preference* pref =
GetPrefs()->FindPreference(kWebTorrentEnabled);
EXPECT_FALSE(pref->HasUserSetting());
brave::SetWebTorrentEnabled(GetProfile(), false);
EXPECT_TRUE(GetPrefs()->GetBoolean(kWebTorrentEnabled));
}
TEST_F(BraveProfileUtilTest, SetWebTorrentEnabledNewProfileNoEntryYet) {
const PrefService::Preference* pref =
GetPrefs()->FindPreference(kWebTorrentEnabled);
EXPECT_FALSE(pref->HasUserSetting());
brave::SetWebTorrentEnabled(GetProfile(), true);
EXPECT_FALSE(GetPrefs()->GetBoolean(kWebTorrentEnabled));
}
// Entry there; ensure value is kept
TEST_F(BraveProfileUtilTest,
SetWebTorrentEnabledExistingProfileHasEntryKeepsValue) {
GetPrefs()->SetBoolean(kWebTorrentEnabled, true);
const PrefService::Preference* pref =
GetPrefs()->FindPreference(kWebTorrentEnabled);
EXPECT_TRUE(pref->HasUserSetting());
brave::SetWebTorrentEnabled(GetProfile(), false);
EXPECT_TRUE(GetPrefs()->GetBoolean(kWebTorrentEnabled));
}
TEST_F(BraveProfileUtilTest, SetWebTorrentEnabledNewProfileHasEntryKeepsValue) {
// This is an anomaly case; new profile won't ever have a hard set value
GetPrefs()->SetBoolean(kWebTorrentEnabled, true);
const PrefService::Preference* pref =
GetPrefs()->FindPreference(kWebTorrentEnabled);
EXPECT_TRUE(pref->HasUserSetting());
brave::SetWebTorrentEnabled(GetProfile(), true);
EXPECT_TRUE(GetPrefs()->GetBoolean(kWebTorrentEnabled));
}
#endif // ENABLE_BRAVE_WEBTORRENT
-7
View File
@@ -45,7 +45,6 @@ import("//brave/components/ai_rewriter/common/buildflags/buildflags.gni")
import("//brave/components/brave_education/buildflags.gni")
import("//brave/components/brave_vpn/common/buildflags/buildflags.gni")
import("//brave/components/brave_wayback_machine/buildflags/buildflags.gni")
import("//brave/components/brave_webtorrent/browser/buildflags/buildflags.gni")
import("//brave/components/commander/common/buildflags/buildflags.gni")
import("//brave/components/containers/buildflags/buildflags.gni")
import("//brave/components/tor/buildflags/buildflags.gni")
@@ -184,7 +183,6 @@ brave_chrome_browser_deps = [
"//brave/components/brave_wallet/common:mojom",
"//brave/components/brave_wallet/common:pref_names",
"//brave/components/brave_wayback_machine/buildflags",
"//brave/components/brave_webtorrent/browser/buildflags",
"//brave/components/commander/common/buildflags",
"//brave/components/constants",
"//brave/components/containers/buildflags",
@@ -461,11 +459,6 @@ if (enable_extensions) {
"//extensions/browser",
"//extensions/common:common_constants",
]
if (enable_brave_webtorrent) {
brave_chrome_browser_deps +=
[ "//brave/components/brave_webtorrent/browser" ]
}
}
if (enable_brave_wayback_machine) {
-1
View File
@@ -33,7 +33,6 @@ source_set("impl") {
":util",
"//base",
"//brave/browser:browser_process",
"//brave/components/brave_webtorrent/browser/buildflags",
"//brave/components/constants",
"//brave/components/tor",
"//brave/components/tor:common",
-1
View File
@@ -20,7 +20,6 @@ source_set("unit_tests") {
"//base",
"//base/test:test_support",
"//brave/browser/tor",
"//brave/components/brave_webtorrent/browser/buildflags",
"//brave/components/constants",
"//brave/components/tor",
"//brave/components/tor:test_support",
@@ -9,7 +9,6 @@
#include "base/memory/raw_ptr.h"
#include "base/test/bind.h"
#include "brave/components/brave_webtorrent/browser/buildflags/buildflags.h"
#include "brave/components/constants/pref_names.h"
#include "chrome/browser/devtools/devtools_window.h"
#include "chrome/browser/media/router/media_router_feature.h"
@@ -77,10 +76,6 @@ TEST_F(TorProfileManagerUnitTest, InitTorProfileUserPrefs) {
EXPECT_FALSE(
tor_profile->GetPrefs()->GetBoolean(prefs::kSafeBrowsingEnabled));
#if BUILDFLAG(ENABLE_BRAVE_WEBTORRENT)
EXPECT_FALSE(tor_profile->GetPrefs()->GetBoolean(kWebTorrentEnabled));
#endif
// Check translate.enabled for translate bubble.
EXPECT_FALSE(tor_profile->GetPrefs()->GetBoolean(
translate::prefs::kOfferTranslateEnabled));
-2
View File
@@ -249,8 +249,6 @@ void TorProfileManager::InitTorProfileUserPrefs(Profile* profile) {
if (base::FeatureList::IsEnabled(net::features::kBraveTorWindowsHttpsOnly)) {
pref_service->SetBoolean(prefs::kHttpsOnlyModeEnabled, true);
}
// https://blog.torproject.org/bittorrent-over-tor-isnt-good-idea
pref_service->SetBoolean(kWebTorrentEnabled, false);
// Disable the automatic translate bubble in Tor because we currently don't
// support extensions in Tor mode and users cannot disable this through
-1
View File
@@ -945,7 +945,6 @@ source_set("ui") {
deps += [
"//brave/app/theme:brave_theme_resources",
"//brave/app/theme:brave_unscaled_resources",
"//brave/components/brave_webtorrent:static_resources",
"//brave/components/webcompat_reporter/browser",
"//brave/components/webcompat_reporter/ui:generated_resources",
]
-1
View File
@@ -3,7 +3,6 @@ include_rules = [
"+brave/components/brave_shields/core/browser",
"+brave/components/ntp_background_images/common",
"+brave/components/brave_ads/core/browser/service",
"+brave/components/brave_webtorrent/grit",
"+brave/components/email_aliases",
"+brave/components/version_info",
"+brave/components/sync/service",
-3
View File
@@ -32,9 +32,6 @@ const start = (
if (options.disable_pdfjs_extension) {
braveArgs.push('--disable-pdfjs-extension')
}
if (options.disable_webtorrent_extension) {
braveArgs.push('--disable-webtorrent-extension')
}
if (options.ui_mode) {
braveArgs.push(`--ui-mode=${options.ui_mode}`)
}
-4
View File
@@ -269,10 +269,6 @@ program
'disable loading the Brave Rewards extension',
)
.option('--disable_pdfjs_extension', 'disable loading the PDFJS extension')
.option(
'--disable_webtorrent_extension',
'disable loading the WebTorrent extension',
)
.option(
'--ui_mode <ui_mode>',
'which built-in ui appearance mode to use',
@@ -1,5 +1,3 @@
include_rules = [
"+brave/components/brave_extension",
"+brave/components/brave_webtorrent/browser/buildflags",
"+brave/components/brave_webtorrent/grit",
]
@@ -7,26 +7,10 @@
#include "brave/components/brave_extension/grit/brave_extension_generated_map.h"
#include "brave/components/brave_extension/grit/brave_extension_resources_map.h"
#include "brave/components/brave_webtorrent/browser/buildflags/buildflags.h"
#if BUILDFLAG(ENABLE_BRAVE_WEBTORRENT)
#include "brave/components/brave_webtorrent/grit/brave_webtorrent_generated_map.h"
#include "brave/components/brave_webtorrent/grit/brave_webtorrent_resources_map.h"
#endif
#if BUILDFLAG(ENABLE_BRAVE_WEBTORRENT)
#define BRAVE_WEBTORRENT_RESOURCES \
AddComponentResourceEntries(kBraveWebtorrentResources); \
AddComponentResourceEntries(kBraveWebtorrentGenerated);
#else
#define BRAVE_WEBTORRENT_RESOURCES
#endif
#define BRAVE_CHROME_COMPONENT_EXTENSION_RESOURCE_MANAGER_DATA_DATA \
AddComponentResourceEntries(kBraveExtension); \
AddComponentResourceEntries(kBraveExtensionGenerated); \
BRAVE_WEBTORRENT_RESOURCES
AddComponentResourceEntries(kBraveExtensionGenerated);
#include "src/chrome/browser/extensions/chrome_component_extension_resource_manager.cc"
#undef BRAVE_CHROME_COMPONENT_EXTENSION_RESOURCE_MANAGER_DATA_DATA
#undef BRAVE_WEBTORRENT_RESOURCES
@@ -10,17 +10,13 @@
#undef IsComponentExtensionAllowlisted
#include "brave/components/brave_extension/grit/brave_extension.h"
#include "brave/components/brave_webtorrent/grit/brave_webtorrent_resources.h"
#include "components/grit/brave_components_resources.h"
#include "extensions/common/constants.h"
namespace extensions {
bool IsComponentExtensionAllowlisted(const std::string& extension_id) {
const char* const kAllowed[] = {
brave_extension_id,
brave_webtorrent_extension_id
};
const char* const kAllowed[] = {brave_extension_id};
for (const auto* id : kAllowed) {
if (extension_id == id) {
@@ -35,7 +31,6 @@ namespace extensions {
switch (manifest_resource_id) {
// Please keep the list in alphabetical order.
case IDR_BRAVE_EXTENSION:
case IDR_BRAVE_WEBTORRENT:
return true;
}
@@ -1,3 +0,0 @@
include_rules = [
"+brave/components/brave_webtorrent/browser",
]
@@ -1,51 +0,0 @@
// Copyright (c) 2023 The Brave Authors. All rights reserved.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
#include <optional>
#include "brave/components/brave_webtorrent/browser/buildflags/buildflags.h"
#include "chrome/browser/external_protocol/external_protocol_handler.h"
#if BUILDFLAG(ENABLE_BRAVE_WEBTORRENT)
#include "brave/components/brave_webtorrent/browser/magnet_protocol_handler.h"
#endif // BUILDFLAG(ENABLE_BRAVE_WEBTORRENT)
#define LaunchUrl LaunchUrl_ChromiumImpl
#include "src/chrome/browser/external_protocol/external_protocol_handler.cc"
#undef LaunchUrl
// static
void ExternalProtocolHandler::LaunchUrl(
const GURL& url,
content::WebContents::Getter web_contents_getter,
ui::PageTransition page_transition,
bool has_user_gesture,
bool is_in_fenced_frame_tree,
const std::optional<url::Origin>& initiating_origin,
content::WeakDocumentPtr initiator_document
#if BUILDFLAG(IS_ANDROID)
,
mojo::PendingRemote<network::mojom::URLLoaderFactory>* out_factory
#endif
) {
#if BUILDFLAG(ENABLE_BRAVE_WEBTORRENT)
if (webtorrent::HandleMagnetProtocol(
url, web_contents_getter, page_transition, has_user_gesture,
is_in_fenced_frame_tree, initiating_origin, initiator_document)) {
return;
}
#endif
LaunchUrl_ChromiumImpl(url, web_contents_getter, page_transition,
has_user_gesture, is_in_fenced_frame_tree,
initiating_origin, initiator_document
#if BUILDFLAG(IS_ANDROID)
,
out_factory
#endif
);
}
@@ -1,17 +0,0 @@
// Copyright (c) 2023 The Brave Authors. All rights reserved.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
#ifndef BRAVE_CHROMIUM_SRC_CHROME_BROWSER_EXTERNAL_PROTOCOL_EXTERNAL_PROTOCOL_HANDLER_H_
#define BRAVE_CHROMIUM_SRC_CHROME_BROWSER_EXTERNAL_PROTOCOL_EXTERNAL_PROTOCOL_HANDLER_H_
#define LaunchUrl(...) \
LaunchUrl_ChromiumImpl(__VA_ARGS__); \
static void LaunchUrl(__VA_ARGS__)
#include "src/chrome/browser/external_protocol/external_protocol_handler.h" // IWYU pragma: export
#undef LaunchUrl
#endif // BRAVE_CHROMIUM_SRC_CHROME_BROWSER_EXTERNAL_PROTOCOL_EXTERNAL_PROTOCOL_HANDLER_H_
-5
View File
@@ -3,7 +3,6 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
import("//brave/components/brave_webtorrent/browser/buildflags/buildflags.gni")
import("//build/config/ui.gni")
group("ui") {
@@ -21,8 +20,4 @@ group("ui") {
"//brave/components/sidebar/browser",
]
}
if (enable_brave_webtorrent) {
deps += [ "//brave/components/brave_webtorrent/browser" ]
}
}
-1
View File
@@ -5,5 +5,4 @@ include_rules += [
"+brave/components/vector_icons",
"+brave/components/commander/common",
"+brave/components/constants",
"+brave/components/brave_webtorrent/browser",
]
@@ -1,71 +0,0 @@
/* Copyright (c) 2020 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <optional>
#include "brave/components/brave_webtorrent/browser/buildflags/buildflags.h"
#include "chrome/browser/ui/browser_tabrestore.h"
#if BUILDFLAG(ENABLE_BRAVE_WEBTORRENT)
#include "brave/browser/extensions/brave_component_loader.h"
#include "brave/browser/extensions/brave_webtorrent_navigation_throttle.h"
#include "brave/components/brave_webtorrent/browser/webtorrent_util.h"
#include "chrome/browser/extensions/extension_service.h"
#include "extensions/browser/extension_system.h"
#endif
#define AddRestoredTab AddRestoredTab_ChromiumImpl
#include "src/chrome/browser/ui/browser_tabrestore.cc"
#undef AddRestoredTab
namespace {
#if BUILDFLAG(ENABLE_BRAVE_WEBTORRENT)
void MaybeLoadWebtorrent(Browser* browser,
bool from_session_restore,
const GURL& restore_url) {
if (!from_session_restore || !webtorrent::IsWebtorrentURL(restore_url))
return;
extensions::BraveWebTorrentNavigationThrottle::MaybeLoadWebtorrent(
browser->profile(), restore_url);
}
#endif
} // namespace
namespace chrome {
WebContents* AddRestoredTab(
Browser* browser,
const std::vector<SerializedNavigationEntry>& navigations,
int tab_index,
int selected_navigation,
const std::string& extension_app_id,
std::optional<tab_groups::TabGroupId> group,
bool select,
bool pin,
base::TimeTicks last_active_time_ticks,
base::Time last_active_time,
content::SessionStorageNamespace* session_storage_namespace,
const sessions::SerializedUserAgentOverride& user_agent_override,
const std::map<std::string, std::string>& extra_data,
bool from_session_restore,
std::optional<bool> is_active_browser) {
#if BUILDFLAG(ENABLE_BRAVE_WEBTORRENT)
MaybeLoadWebtorrent(
browser,
from_session_restore,
navigations.at(selected_navigation).original_request_url());
#endif
return AddRestoredTab_ChromiumImpl(
browser, navigations, tab_index, selected_navigation, extension_app_id,
group, select, pin, last_active_time_ticks, last_active_time,
session_storage_namespace, user_agent_override, extra_data,
from_session_restore, is_active_browser);
}
} // namespace chrome
@@ -1,3 +0,0 @@
include_rules = [
"+brave/components/brave_webtorrent/browser",
]
@@ -1,30 +0,0 @@
// Copyright (c) 2023 The Brave Authors. All rights reserved.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
#include "brave/components/brave_webtorrent/browser/buildflags/buildflags.h"
#include "components/grit/brave_components_strings.h"
#include "components/page_info/page_info.h"
#include "content/public/common/url_constants.h"
#if BUILDFLAG(ENABLE_BRAVE_WEBTORRENT)
#include "brave/components/brave_webtorrent/browser/magnet_protocol_handler.h"
// Show the InternalPageInfoBubbleView when viewing a page with the webtorrent
// scheme.
#define IsFileOrInternalPage(url) \
IsFileOrInternalPage(url) || url.SchemeIs(url::kWebTorrentScheme)
// Set the text for the InternalPageInfoBubbleView on webtorrent: pages.
#define kFileScheme kWebTorrentScheme)) { \
text = IDS_PAGE_INFO_BRAVE_WEBTORRENT; \
} \
else if (url.SchemeIs(url::kFileScheme
#endif
#include "src/chrome/browser/ui/views/page_info/page_info_bubble_view.cc"
#undef kFileScheme
#undef IsFileOrInternalPage
@@ -14,13 +14,6 @@ inline constexpr char brave_extension_id[] = "mnojpmjdmbbfmejpflffifhffcmidifd";
inline constexpr char crl_set_extension_id[] =
"hfnkpimlhhgieaddgfemjhofmfblmnib";
inline constexpr char brave_webtorrent_extension_id[] =
"lgjmpdmojkpocjcopdikifhejkkjglho";
inline constexpr char brave_webtorrent_extension_filename[] =
"brave_webtorrent.html";
inline constexpr char brave_webtorrent_extension_filename2[] =
"brave_webtorrent2.html";
inline constexpr char google_translate_extension_id[] =
"aapbdbdomjkkjkaonfhkkikfgjllcleb";
-42
View File
@@ -1,42 +0,0 @@
# Copyright (c) 2018 The Brave Authors. All rights reserved.
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at https://mozilla.org/MPL/2.0/.
import("//brave/components/common/typescript.gni")
import("//brave/resources/brave_grit.gni")
import("//tools/grit/repack.gni")
assert(!is_android && !is_ios)
brave_grit("static_resources") {
source = "resources.grd"
outputs = [
"grit/brave_webtorrent_resources_map.cc",
"grit/brave_webtorrent_resources_map.h",
"grit/brave_webtorrent_resources.h",
"brave_webtorrent_static.pak",
]
}
pack_web_resources("generated_resources") {
resource_name = "brave_webtorrent"
output_dir = "$root_gen_dir/brave/components/brave_webtorrent"
# Need wepack and GRD generation first
deps = [ "extension:generate_brave_webtorrent" ]
}
repack("resources") {
deps = [
":generated_resources",
":static_resources",
]
sources = [
"$root_gen_dir/brave/components/brave_webtorrent/brave_webtorrent_generated.pak",
"$root_gen_dir/brave/components/brave_webtorrent/brave_webtorrent_static.pak",
]
# This output repacked by brave_paks.gni
output = "$root_gen_dir/brave/components/brave_webtorrent/brave_webtorrent_resources.pak"
}
@@ -1,31 +0,0 @@
# Copyright (c) 2018 The Brave Authors. All rights reserved.
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at https://mozilla.org/MPL/2.0/.
import("//extensions/buildflags/buildflags.gni")
assert(enable_extensions)
static_library("browser") {
sources = [
"magnet_protocol_handler.cc",
"magnet_protocol_handler.h",
"webtorrent_util.cc",
"webtorrent_util.h",
]
deps = [
"//base",
"//brave/components/constants",
"//components/pref_registry",
"//components/prefs",
"//content/public/browser",
"//extensions/browser",
"//extensions/buildflags",
"//extensions/common",
"//net",
]
public_deps = [ "buildflags" ]
}
@@ -1,10 +0,0 @@
import("//build/buildflag_header.gni")
import("buildflags.gni")
buildflag_header("buildflags") {
header = "buildflags.h"
flags = [
"ENABLE_BRAVE_WEBTORRENT=$enable_brave_webtorrent",
]
}
@@ -1,10 +0,0 @@
# Copyright (c) 2025 The Brave Authors. All rights reserved.
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at https://mozilla.org/MPL/2.0/.
import("//extensions/buildflags/buildflags.gni")
declare_args() {
enable_brave_webtorrent = false
}
@@ -1,159 +0,0 @@
/* Copyright (c) 2023 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/. */
#include "brave/components/brave_webtorrent/browser/magnet_protocol_handler.h"
#include <optional>
#include <string>
#include <utility>
#include "base/check.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/escape.h"
#include "base/strings/strcat.h"
#include "base/strings/string_util.h"
#include "brave/components/brave_webtorrent/browser/webtorrent_util.h"
#include "brave/components/constants/url_constants.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/weak_document_ptr.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/common/constants.h"
#include "ui/base/page_transition_types.h"
namespace webtorrent {
namespace {
constexpr char kWebtorrentUsageHistogramName[] = "Brave.WebTorrent.UsageWeekly";
bool IsMagnetProtocol(const GURL& url) {
return url.SchemeIs(kMagnetScheme);
}
void LoadMagnetURL(const GURL& url,
content::WebContents::Getter web_contents_getter,
ui::PageTransition page_transition,
bool has_user_gesture,
bool is_in_fenced_frame_tree,
const std::optional<url::Origin>& initiating_origin,
content::WeakDocumentPtr initiator_document) {
content::WebContents* web_contents = web_contents_getter.Run();
if (!web_contents) {
return;
}
DCHECK(IsMagnetProtocol(url));
DCHECK(IsWebtorrentEnabled(web_contents->GetBrowserContext()));
page_transition = ui::PageTransitionIsMainFrame(page_transition)
? page_transition
: ui::PageTransition::PAGE_TRANSITION_AUTO_TOPLEVEL;
web_contents->GetController().LoadURL(url, content::Referrer(),
page_transition, std::string());
}
} // namespace
GURL TranslateMagnetURL(const GURL& url) {
GURL extension_page_url(base::StrCat(
{extensions::kExtensionScheme, "://", brave_webtorrent_extension_id,
"/extension/brave_webtorrent.html?%s"}));
std::string translatedSpec(extension_page_url.spec());
base::ReplaceFirstSubstringAfterOffset(
&translatedSpec, 0, "%s", base::EscapeQueryParamValue(url.spec(), true));
return GURL(translatedSpec);
}
GURL TranslateTorrentUIURLReversed(const GURL& url) {
GURL translated_url(base::UnescapeURLComponent(
url.query(),
base::UnescapeRule::URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS |
base::UnescapeRule::PATH_SEPARATORS));
GURL::Replacements replacements;
replacements.SetRefStr(url.ref_piece());
return GURL(
base::StrCat({url::kWebTorrentScheme, ":",
translated_url.ReplaceComponents(replacements).spec()}));
}
bool HandleTorrentURLReverseRewrite(GURL* url,
content::BrowserContext* browser_context) {
if (url->SchemeIs(extensions::kExtensionScheme) &&
url->host() == brave_webtorrent_extension_id &&
url->ExtractFileName() == "brave_webtorrent.html" &&
GURL(url->query()).SchemeIsHTTPOrHTTPS()) {
*url = TranslateTorrentUIURLReversed(*url);
return true;
}
return false;
}
bool HandleTorrentURLRewrite(GURL* url,
content::BrowserContext* browser_context) {
if (!IsWebtorrentEnabled(browser_context)) {
return false;
}
// The HTTP/HTTPS URL could be modified later by the network delegate if the
// mime type matches or .torrent is in the path.
// Handle http and https here for making reverse_on_redirect to be true in
// BrowserURLHandlerImpl::RewriteURLIfNecessary to trigger ReverseURLRewrite
// for updating the virtual URL.
if (url->SchemeIsHTTPOrHTTPS() ||
(url->SchemeIs(extensions::kExtensionScheme) &&
url->host() == brave_webtorrent_extension_id &&
url->ExtractFileName() == "brave_webtorrent.html" &&
GURL(url->query()).SchemeIsHTTPOrHTTPS())) {
return true;
}
return false;
}
bool HandleMagnetURLRewrite(GURL* url,
content::BrowserContext* browser_context) {
if (IsWebtorrentEnabled(browser_context) && IsMagnetProtocol(*url)) {
*url = TranslateMagnetURL(*url);
return true;
}
return false;
}
bool HandleMagnetProtocol(const GURL& url,
content::WebContents::Getter web_contents_getter,
ui::PageTransition page_transition,
bool has_user_gesture,
bool is_in_fenced_frame_tree,
const std::optional<url::Origin>& initiating_origin,
content::WeakDocumentPtr initiator_document) {
if (!IsMagnetProtocol(url)) {
return false;
}
// Handle subframe magnet links only if a user gesture is present.
if (!ui::PageTransitionIsMainFrame(page_transition) && !has_user_gesture) {
return false;
}
content::WebContents* web_contents = web_contents_getter.Run();
if (!web_contents ||
!IsWebtorrentEnabled(web_contents->GetBrowserContext())) {
return false;
}
UMA_HISTOGRAM_BOOLEAN(kWebtorrentUsageHistogramName, true);
content::GetUIThreadTaskRunner({})->PostTask(
FROM_HERE,
base::BindOnce(&LoadMagnetURL, url, web_contents_getter, page_transition,
has_user_gesture, is_in_fenced_frame_tree,
initiating_origin, std::move(initiator_document)));
return true;
}
} // namespace webtorrent
@@ -1,46 +0,0 @@
/* Copyright (c) 2023 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/. */
#ifndef BRAVE_COMPONENTS_BRAVE_WEBTORRENT_BROWSER_MAGNET_PROTOCOL_HANDLER_H_
#define BRAVE_COMPONENTS_BRAVE_WEBTORRENT_BROWSER_MAGNET_PROTOCOL_HANDLER_H_
#include <optional>
#include "brave/components/brave_webtorrent/browser/webtorrent_util.h"
#include "content/public/browser/weak_document_ptr.h"
#include "content/public/browser/web_contents.h"
#include "ui/base/page_transition_types.h"
// Define this variable in the url namespace to make patching easier.
namespace url {
inline constexpr char kWebTorrentScheme[] = "webtorrent";
} // namespace url
namespace webtorrent {
GURL TranslateMagnetURL(const GURL& url);
GURL TranslateTorrentUIURLReversed(const GURL& url);
bool HandleTorrentURLReverseRewrite(GURL* url,
content::BrowserContext* browser_context);
bool HandleTorrentURLRewrite(GURL* url,
content::BrowserContext* browser_context);
bool HandleMagnetURLRewrite(GURL* url,
content::BrowserContext* browser_context);
bool HandleMagnetProtocol(const GURL& url,
content::WebContents::Getter web_contents_getter,
ui::PageTransition page_transition,
bool has_user_gesture,
bool is_in_fenced_frame_tree,
const std::optional<url::Origin>& initiating_origin,
content::WeakDocumentPtr initiator_document);
} // namespace webtorrent
#endif // BRAVE_COMPONENTS_BRAVE_WEBTORRENT_BROWSER_MAGNET_PROTOCOL_HANDLER_H_
@@ -1,91 +0,0 @@
/* Copyright (c) 2019 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "brave/components/brave_webtorrent/browser/webtorrent_util.h"
#include <string>
#include "base/strings/string_util.h"
#include "brave/components/constants/network_constants.h"
#include "brave/components/constants/pref_names.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/pref_service.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/common/constants.h"
#include "net/http/http_content_disposition.h"
#include "net/http/http_response_headers.h"
namespace webtorrent {
bool TorrentFileNameMatched(const net::HttpResponseHeaders* headers) {
std::optional<std::string> disposition =
headers->GetNormalizedHeader("Content-Disposition");
if (!disposition) {
return false;
}
net::HttpContentDisposition cd_headers(*disposition, std::string());
if (base::EndsWith(cd_headers.filename(), ".torrent",
base::CompareCase::INSENSITIVE_ASCII) ||
base::EndsWith(cd_headers.filename(), ".torrent\"",
base::CompareCase::INSENSITIVE_ASCII)) {
return true;
}
return false;
}
bool TorrentURLMatched(const GURL& url) {
return base::EndsWith(url.path(), ".torrent",
base::CompareCase::INSENSITIVE_ASCII);
}
bool IsWebtorrentEnabled(content::BrowserContext* browser_context) {
extensions::ExtensionRegistry* registry =
extensions::ExtensionRegistry::Get(browser_context);
if (!registry) {
return false;
}
return registry->enabled_extensions().Contains(brave_webtorrent_extension_id);
}
void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
registry->RegisterBooleanPref(kWebTorrentEnabled, true);
}
bool IsWebtorrentURL(const GURL& url) {
if (url.SchemeIs(extensions::kExtensionScheme) &&
url.host() == brave_webtorrent_extension_id &&
(url.ExtractFileName() == brave_webtorrent_extension_filename ||
url.ExtractFileName() == brave_webtorrent_extension_filename2)) {
return true;
}
return false;
}
bool IsTorrentFile(const GURL& url, const net::HttpResponseHeaders* headers) {
if (!headers) {
return false;
}
std::string mimeType;
if (!headers->GetMimeType(&mimeType)) {
return false;
}
if (mimeType == kBittorrentMimeType) {
return true;
}
if (mimeType == kOctetStreamMimeType &&
(TorrentURLMatched(url) || TorrentFileNameMatched(headers))) {
return true;
}
return false;
}
} // namespace webtorrent
@@ -1,33 +0,0 @@
/* Copyright (c) 2019 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/. */
#ifndef BRAVE_COMPONENTS_BRAVE_WEBTORRENT_BROWSER_WEBTORRENT_UTIL_H_
#define BRAVE_COMPONENTS_BRAVE_WEBTORRENT_BROWSER_WEBTORRENT_UTIL_H_
class GURL;
namespace content {
class BrowserContext;
}
namespace user_prefs {
class PrefRegistrySyncable;
}
namespace net {
class HttpResponseHeaders;
}
namespace webtorrent {
bool IsWebtorrentEnabled(content::BrowserContext* browser_context);
void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
bool IsWebtorrentURL(const GURL& url);
bool IsTorrentFile(const GURL& url, const net::HttpResponseHeaders* headers);
bool TorrentURLMatched(const GURL& url);
} // namespace webtorrent
#endif // BRAVE_COMPONENTS_BRAVE_WEBTORRENT_BROWSER_WEBTORRENT_UTIL_H_
@@ -1,30 +0,0 @@
# Copyright (c) 2018 The Brave Authors. All rights reserved.
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at https://mozilla.org/MPL/2.0/.
import("//brave/components/common/typescript.gni")
transpile_web_ui("generate_brave_webtorrent") {
entry_points = [
[
"brave_webtorrent",
rebase_path("brave_webtorrent.tsx"),
],
[
"brave_webtorrent_background",
rebase_path("background.ts"),
],
]
# For explanation of "chromeapp", see:
# https://github.com/brave/brave-browser/issues/5587
webpack_aliases = [ "chromeapp" ]
resource_name = "brave_webtorrent"
# Must match the relative path from the static GRD to the manifest.json
# plus any other relative path we want these files to live in the extension
resource_path_prefix = "brave_webtorrent/extension/out"
public_asset_path = "/extension/out/"
}
@@ -1,22 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/. */
import { action } from 'typesafe-actions'
// Constants
import { types } from '../constants/tab_types'
export const tabUpdated = (tabId: number,
changeInfo: { url: string }) =>
action(types.TAB_UPDATED, {
tabId, changeInfo
})
export const tabRemoved = (tabId: number) => action(types.TAB_REMOVED, {
tabId
})
export const tabRetrieved = (tab: chrome.tabs.Tab) => action(types.TAB_RETRIEVED, {
tab
})
@@ -1,19 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/. */
import { action } from 'typesafe-actions'
import { Torrent } from 'webtorrent'
import { Instance } from 'parse-torrent'
// Constants
import { types } from '../constants/webtorrent_types'
export const progressUpdated = (torrent: Torrent) => action(types.WEBTORRENT_PROGRESS_UPDATED, { torrent })
export const infoUpdated = (torrent: Torrent) => action(types.WEBTORRENT_INFO_UPDATED, { torrent })
export const serverUpdated = (torrent: Torrent, serverURL: string) =>
action(types.WEBTORRENT_SERVER_UPDATED, { torrent, serverURL })
export const startTorrent = (torrentId: string, tabId: number) => action(types.WEBTORRENT_START_TORRENT, { torrentId, tabId })
export const stopDownload = (tabId: number) => action(types.WEBTORRENT_STOP_DOWNLOAD, { tabId })
export const torrentParsed = (torrentId: string, tabId: number, infoHash: string | undefined, errorMsg: string | undefined, parsedTorrent?: Instance) => action(types.WEBTORRENT_TORRENT_PARSED, { torrentId, tabId, infoHash, errorMsg, parsedTorrent })
export const saveAllFiles = (infoHash: string) => action(types.WEBTORRENT_SAVE_ALL_FILES, { infoHash })
@@ -1,17 +0,0 @@
<svg viewBox="0 0 148 28" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<path d="M0 6.635v10.96a1 1 0 0 0 .5.867l9.492 5.48a1 1 0 0 0 1 0l9.492-5.48a1 1 0 0 0 .5-.866V6.635a1 1 0 0 0-.5-.866L10.992.289a1 1 0 0 0-1 0L.5 5.769a1 1 0 0 0-.5.866z" id="path-1"/>
</defs>
<g fill="none" fill-rule="evenodd">
<path d="M11.5.289l-11 6.35a1 1 0 0 0-.5.867v12.701a1 1 0 0 0 .5.866l11 6.351a1 1 0 0 0 1 0l11-6.35a1 1 0 0 0 .5-.867V7.506a1 1 0 0 0-.5-.866L12.5.289a1 1 0 0 0-1 0z" fill="#EF334C"/>
<g transform="translate(1.508 1.741)">
<mask id="mask-2" fill="#fff">
<use xlink:href="#path-1"/>
</mask>
<use fill="#343B45" xlink:href="#path-1"/>
<path fill="#262B33" mask="url(#mask-2)" d="M10.492 17.259l6 6 6-4v-4l-7-7z"/>
</g>
<path d="M15.462 9.126C12.923 8.549 12 10.74 12 10.74s-.923-2.192-3.462-1.615c-2.538.577-3.115 4.154 0 6.923C11.654 18.818 12 19.164 12 19.164s.346-.346 3.462-3.115c3.115-2.77 2.538-6.346 0-6.923" fill="#EF334C"/>
<path d="M51.46 6.76h2.48L48.9 21h-2.1l-3.58-10.24L39.6 21h-2.1L32.48 6.76h2.62l3.56 10.62 3.7-10.62h1.84l3.62 10.7 3.64-10.7zm11.94 9.32h-6.96c.053 1.08.323 1.877.81 2.39.487.513 1.21.77 2.17.77 1.107 0 2.133-.36 3.08-1.08l.72 1.72c-.48.387-1.07.697-1.77.93-.7.233-1.41.35-2.13.35-1.653 0-2.953-.467-3.9-1.4-.947-.933-1.42-2.213-1.42-3.84 0-1.027.207-1.94.62-2.74.413-.8.993-1.423 1.74-1.87.747-.447 1.593-.67 2.54-.67 1.387 0 2.483.45 3.29 1.35.807.9 1.21 2.137 1.21 3.71v.38zm-4.44-3.64c-.667 0-1.21.197-1.63.59-.42.393-.69.963-.81 1.71h4.7c-.08-.76-.31-1.333-.69-1.72-.38-.387-.903-.58-1.57-.58zm12.8-1.8c.88 0 1.657.217 2.33.65.673.433 1.197 1.043 1.57 1.83.373.787.56 1.7.56 2.74 0 1.04-.19 1.963-.57 2.77-.38.807-.907 1.43-1.58 1.87-.673.44-1.443.66-2.31.66-.747 0-1.41-.16-1.99-.48a3.135 3.135 0 0 1-1.31-1.34V21H66V6.28h2.48v6.14c.307-.56.747-.997 1.32-1.31.573-.313 1.227-.47 1.96-.47zm-.66 8.56c.827 0 1.467-.293 1.92-.88.453-.587.68-1.407.68-2.46 0-1.04-.227-1.843-.68-2.41-.453-.567-1.1-.85-1.94-.85-.84 0-1.487.287-1.94.86-.453.573-.68 1.387-.68 2.44 0 1.067.227 1.883.68 2.45.453.567 1.107.85 1.96.85zM81.64 21V8.88H77V6.76h11.9v2.12h-4.66V21h-2.6zm11.5.16c-1.027 0-1.93-.213-2.71-.64a4.371 4.371 0 0 1-1.8-1.83c-.42-.793-.63-1.723-.63-2.79s.21-1.997.63-2.79a4.371 4.371 0 0 1 1.8-1.83c.78-.427 1.683-.64 2.71-.64 1.013 0 1.907.213 2.68.64a4.387 4.387 0 0 1 1.79 1.83c.42.793.63 1.723.63 2.79s-.21 1.997-.63 2.79a4.387 4.387 0 0 1-1.79 1.83c-.773.427-1.667.64-2.68.64zm-.02-1.96c.853 0 1.503-.277 1.95-.83.447-.553.67-1.377.67-2.47 0-1.08-.227-1.903-.68-2.47-.453-.567-1.093-.85-1.92-.85-.84 0-1.487.283-1.94.85-.453.567-.68 1.39-.68 2.47 0 1.093.223 1.917.67 2.47.447.553 1.09.83 1.93.83zm13.48-8.54c.387 0 .72.053 1 .16l-.02 2.28a3.476 3.476 0 0 0-1.32-.26c-.853 0-1.503.247-1.95.74-.447.493-.67 1.147-.67 1.96V21h-2.48v-7.24c0-1.067-.053-2.02-.16-2.86h2.34l.2 1.78c.253-.653.653-1.153 1.2-1.5a3.4 3.4 0 0 1 1.86-.52zm9 0c.387 0 .72.053 1 .16l-.02 2.28a3.476 3.476 0 0 0-1.32-.26c-.853 0-1.503.247-1.95.74-.447.493-.67 1.147-.67 1.96V21h-2.48v-7.24c0-1.067-.053-2.02-.16-2.86h2.34l.2 1.78c.253-.653.653-1.153 1.2-1.5a3.4 3.4 0 0 1 1.86-.52zm12.26 5.42h-6.96c.053 1.08.323 1.877.81 2.39.487.513 1.21.77 2.17.77 1.107 0 2.133-.36 3.08-1.08l.72 1.72c-.48.387-1.07.697-1.77.93-.7.233-1.41.35-2.13.35-1.653 0-2.953-.467-3.9-1.4-.947-.933-1.42-2.213-1.42-3.84 0-1.027.207-1.94.62-2.74.413-.8.993-1.423 1.74-1.87.747-.447 1.593-.67 2.54-.67 1.387 0 2.483.45 3.29 1.35.807.9 1.21 2.137 1.21 3.71v.38zm-4.44-3.64c-.667 0-1.21.197-1.63.59-.42.393-.69.963-.81 1.71h4.7c-.08-.76-.31-1.333-.69-1.72-.38-.387-.903-.58-1.57-.58zm12.34-1.8c2.413 0 3.62 1.387 3.62 4.16V21h-2.5v-6.08c0-.8-.153-1.383-.46-1.75-.307-.367-.78-.55-1.42-.55-.76 0-1.373.243-1.84.73-.467.487-.7 1.13-.7 1.93V21h-2.48v-7.24c0-1.067-.053-2.02-.16-2.86h2.34l.18 1.66a3.655 3.655 0 0 1 1.41-1.42c.593-.333 1.263-.5 2.01-.5zm9.46 2.14v4.52c0 1.187.553 1.78 1.66 1.78.307 0 .64-.053 1-.16v1.98c-.44.16-.973.24-1.6.24-1.147 0-2.027-.32-2.64-.96-.613-.64-.92-1.56-.92-2.76v-4.64h-1.94V10.9h1.94V8.44l2.5-.84v3.3h2.68v1.88h-2.68z" fill="#3B3E4F"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.1 KiB

@@ -1,12 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/. */
const locale = {
startDownload: 'Start download',
stopDownload: 'Stop download',
saveTorrentFile: 'Save .torrent file',
startTorrentIntro: 'Click "Start Torrent" to begin your download.'
}
export default locale
@@ -1,8 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/. */
import './background/events/webtorrentEvents'
import './background/events/torrentEvents'
import './background/events/tabsEvents'
import './background/store'
@@ -1,8 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/. */
import { bindActionCreators } from 'redux'
import store from '../store'
import * as tabActions from '../../actions/tab_actions'
export default bindActionCreators(tabActions, store.dispatch)
@@ -1,8 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/. */
import { bindActionCreators } from 'redux'
import store from '../store'
import * as webtorrentActions from '../../actions/webtorrent_actions'
export default bindActionCreators(webtorrentActions, store.dispatch)
@@ -1,24 +0,0 @@
// Copyright (c) 2024 The Brave Authors. All rights reserved.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
import * as ParseTorrent from 'parse-torrent'
export const parseTorrentRemote = (torrentId: string, tabId: number) => {
ParseTorrent.remote(
torrentId,
(err: Error, parsedTorrent?: ParseTorrent.Instance) => {
const webtorrentActions = require('../actions/webtorrentActions').default
const errMsg = err ? err.message : undefined
const infoHash = parsedTorrent ? parsedTorrent.infoHash : undefined
webtorrentActions.torrentParsed(
torrentId,
tabId,
infoHash,
errMsg,
parsedTorrent
)
}
)
}
@@ -1,59 +0,0 @@
// Copyright (c) 2024 The Brave Authors. All rights reserved.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
import tabActions from '../actions/tabActions'
// On initialization, make sure we tell WebTorrent about all existing tabs. This
// fixes a bug where WebTorrent wouldn't load for the first click of magnet
// links (as the background page would not be running on that first load).
// Note: Empty query for {} returns all tabs this extension is interested in.
chrome.tabs.query({}, tabs => {
if (chrome.runtime.lastError) {
console.error('Error querying tabs: ', chrome.runtime.lastError);
return;
}
for (const tab of tabs) {
tabActions.tabUpdated(tab.id!, { url: tab.url ?? '' })
}
})
chrome.webNavigation.onCommitted.addListener(
(details: chrome.webNavigation.WebNavigationFramedCallbackDetails) => {
tabActions.tabUpdated(details.tabId, details)
},
{
url: [
{ pathSuffix: '.torrent' },
// have a magnet scheme
{ schemes: ['magnet'] }]
}
)
chrome.webNavigation.onCommitted.addListener(
(details: chrome.webNavigation.WebNavigationFramedCallbackDetails) => {
// navigation events come in with the webtorrent extension as
// the schema/host, the actual webtorrent URL appended to it
// after the chrome-extenion://extension-id/view.html?
// delete everything up to the first question mark
let original = details.url.replace(new RegExp(/^[^\?]*\?/), '')
let decoded = decodeURIComponent(original)
details.url = decoded
tabActions.tabUpdated(details.tabId, details)
},
{
url: [
// when handling URLs as chrome-extension://...
// the actual torrent URL is within query parameters
{ schemes: ['chrome-extension'], queryContains: '.torrent' },
{ schemes: ['chrome-extension'], queryContains: 'magnet%3A' }]
}
)
chrome.tabs.onRemoved.addListener(
(tabId: number, removeInfo: chrome.tabs.TabRemoveInfo) => {
tabActions.tabRemoved(tabId)
}
)
@@ -1,45 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/. */
import { Torrent } from 'webtorrent'
import * as throttle from 'throttleit'
import webtorrentActions from '../actions/webtorrentActions'
import { createServer } from '../webtorrent'
interface TorrentExtended extends Torrent {
progressInterval?: number
}
export const addTorrentEvents = (torrent: TorrentExtended) => {
torrent.on('warning', (e: Error) => console.log('warning: ', torrent, e))
torrent.on('error', (e: Error) => console.log('error: ', torrent, e))
torrent.on('ready', () => {
createServer(torrent, (serverURL: string) => {
webtorrentActions.serverUpdated(torrent, serverURL)
})
})
torrent.on('infoHash', () => webtorrentActions.infoUpdated(torrent))
torrent.on('metadata', () => webtorrentActions.infoUpdated(torrent))
const progressUpdatedThrottled = throttle((bytes: number) => {
webtorrentActions.progressUpdated(torrent)
}, 500)
torrent.on('download', progressUpdatedThrottled)
torrent.on('upload', progressUpdatedThrottled)
torrent.on('done', progressUpdatedThrottled)
torrent.on('wire', progressUpdatedThrottled)
// Always update stats at least once every 5 seconds, even when no torrent
// events fire. Ensures that download/upload speeds do not get stuck on a
// positive value when the transfer stalls.
torrent.progressInterval = window.setInterval(progressUpdatedThrottled, 5000)
}
export const removeTorrentEvents = (torrent: TorrentExtended) => {
window.clearInterval(torrent.progressInterval)
}
@@ -1,11 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/. */
import { Instance } from 'webtorrent'
export const addWebtorrentEvents = (webtorrent: Instance) => {
webtorrent.on('error', (e: Error) => {
console.log('WebTorrent error: ', e)
})
}
@@ -1,13 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/. */
import { combineReducers } from 'redux'
// Utils
import { webtorrentReducer } from './webtorrent_reducer'
import { ApplicationState } from '../../constants/webtorrentState'
export default combineReducers<ApplicationState>({
torrentsData: webtorrentReducer
})
@@ -1,327 +0,0 @@
// Copyright (c) 2024 The Brave Authors. All rights reserved.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
import * as ParseTorrent from 'parse-torrent'
import { Torrent } from 'webtorrent'
import { parse } from 'querystring'
// Constants
import * as tabTypes from '../../constants/tab_types'
import * as torrentTypes from '../../constants/webtorrent_types'
import {
File,
TorrentState,
TorrentStateMap,
TorrentsState
} from '../../constants/webtorrentState'
// Utils
import {
addTorrent,
delTorrent,
findTorrent,
saveAllFiles as webtorrentSaveAllFiles
} from '../webtorrent'
import { parseTorrentRemote } from '../api/torrent_api'
const tabUpdated = (tabId: number, url: string, state: TorrentsState) => {
const { torrentStateMap, torrentObjMap } = state
const origTorrentState: TorrentState = torrentStateMap[tabId]
const origInfoHash = origTorrentState ? origTorrentState.infoHash : undefined
let newTorrentState: TorrentState | undefined
let newInfoHash: string | undefined
// create new torrent state
const parsedURL = new window.URL(url)
const torrentId = parsedURL.href
if (parsedURL.protocol === 'magnet:') {
// parse torrent
try {
const { name, infoHash, ix } = ParseTorrent(torrentId)
newInfoHash = infoHash
newTorrentState = { tabId, torrentId, name, infoHash, ix }
} catch (error) {
newTorrentState = { tabId, torrentId, errorMsg: error.message }
}
} else if (
parsedURL.protocol === 'https:' ||
parsedURL.protocol === 'http:'
) {
const name = parsedURL.pathname.substr(
parsedURL.pathname.lastIndexOf('/') + 1
)
// for .torrent case, ix (index of file) for selecting a specific file in
// the file list is given in url like #ix=5
let ix: number | undefined = Number(parse(parsedURL.hash.slice(1)).ix)
ix = Number.isNaN(ix) ? undefined : ix
// Use an existing infoHash if it's the same torrentId
const torrentUrl = parsedURL.origin + parsedURL.pathname
const key = (Object.keys(torrentStateMap) as unknown as Array<keyof TorrentStateMap>).find(
(key) =>
torrentStateMap[key].infoHash &&
torrentStateMap[key].torrentId === torrentUrl
)
newInfoHash = key ? torrentStateMap[key].infoHash : undefined
newTorrentState = { tabId, torrentId, name, ix, infoHash: newInfoHash }
}
// delete old torrent state
delete torrentStateMap[tabId]
// unsubscribe old torrent if not the same
const isSameTorrent = newInfoHash && origInfoHash === newInfoHash
if (origInfoHash && torrentObjMap[origInfoHash] && !isSameTorrent) {
torrentObjMap[origInfoHash].tabClients.delete(tabId)
if (!torrentObjMap[origInfoHash].tabClients.size) {
delete torrentObjMap[origInfoHash]
delTorrent(origInfoHash)
}
}
// save new torrent state and subscribe directly if torrent already existed
if (newTorrentState) {
torrentStateMap[tabId] = newTorrentState
if (newInfoHash && torrentObjMap[newInfoHash]) {
torrentObjMap[newInfoHash].tabClients.add(tabId)
}
}
return { ...state, torrentStateMap, torrentObjMap }
}
const tabRemoved = (tabId: number, state: TorrentsState) => {
const { torrentStateMap, torrentObjMap } = state
const torrentState = torrentStateMap[tabId]
if (torrentState) {
const infoHash = torrentState.infoHash
if (infoHash && torrentObjMap[infoHash]) {
// unsubscribe
if (torrentObjMap[infoHash].tabClients) {
torrentObjMap[infoHash].tabClients.delete(tabId)
}
if (!torrentObjMap[infoHash].tabClients.size) {
delete torrentObjMap[infoHash]
delTorrent(infoHash)
}
}
delete torrentStateMap[tabId]
}
return { ...state, torrentStateMap, torrentObjMap }
}
const startTorrent = (
torrentId: string,
tabId: number,
state: TorrentsState
) => {
const { torrentStateMap, torrentObjMap } = state
const torrentState = torrentStateMap[tabId]
// infoHash might not be available yet for .torrent case
if (torrentState && !torrentState.errorMsg && !torrentState.infoHash) {
parseTorrentRemote(torrentId, tabId)
}
if (
torrentState &&
torrentState.infoHash &&
!findTorrent(torrentState.infoHash)
) {
addTorrent(torrentId) // objectMap will be updated when info event is emitted
} else if (
torrentState &&
torrentState.infoHash &&
torrentObjMap[torrentState.infoHash]
) {
torrentObjMap[torrentState.infoHash].tabClients.add(tabId)
}
return { ...state, torrentObjMap }
}
const stopDownload = (tabId: number, state: TorrentsState) => {
const { torrentStateMap, torrentObjMap } = state
const infoHash = torrentStateMap[tabId].infoHash
if (infoHash && torrentObjMap[infoHash]) {
delete torrentObjMap[infoHash]
delTorrent(infoHash)
}
return { ...state, torrentStateMap, torrentObjMap }
}
const updateProgress = (state: TorrentsState, torrent: Torrent) => {
const { torrentObjMap } = state
// don't add a new entry since the download might be stopped already
if (!torrentObjMap[torrent.infoHash]) {
return state
}
const {
downloaded,
uploaded,
downloadSpeed,
uploadSpeed,
progress,
ratio,
numPeers,
timeRemaining
} = torrent
torrentObjMap[torrent.infoHash] = {
...torrentObjMap[torrent.infoHash],
downloaded,
uploaded,
downloadSpeed,
uploadSpeed,
progress,
ratio,
numPeers,
timeRemaining
}
return { ...state, torrentObjMap }
}
const updateInfo = (state: TorrentsState, torrent: Torrent) => {
const { torrentStateMap, torrentObjMap } = state
const {
name,
downloaded,
uploaded,
downloadSpeed,
uploadSpeed,
progress,
ratio,
numPeers,
timeRemaining,
infoHash
} = torrent
let length: number = 0
const files: File[] = torrent.files.map((file) => {
length += file.length
return { name: file.name, length: file.length, path: file.path }
})
const tabClients: Set<number> = new Set<number>()
; (Object.keys(torrentStateMap) as unknown as Array<keyof TorrentStateMap>)
.filter((key) => torrentStateMap[key].infoHash === infoHash)
.map((key) => {
tabClients.add(torrentStateMap[key].tabId)
})
torrentObjMap[torrent.infoHash] = {
...torrentObjMap[torrent.infoHash],
files,
name,
downloaded,
uploaded,
downloadSpeed,
uploadSpeed,
progress,
ratio,
numPeers,
timeRemaining,
length,
tabClients
}
return { ...state, torrentStateMap, torrentObjMap }
}
const updateServer = (
state: TorrentsState,
torrent: Torrent,
serverURL: string
) => {
const { torrentObjMap } = state
torrentObjMap[torrent.infoHash] = {
...torrentObjMap[torrent.infoHash],
serverURL
}
return { ...state, torrentObjMap }
}
const torrentParsed = (
torrentId: string,
tabId: number,
infoHash: string | undefined,
errorMsg: string | undefined,
parsedTorrent: ParseTorrent.Instance | undefined,
state: TorrentsState
) => {
const { torrentObjMap, torrentStateMap } = state
torrentStateMap[tabId] = { ...torrentStateMap[tabId], infoHash, errorMsg }
if (infoHash && !findTorrent(infoHash) && parsedTorrent) {
addTorrent(parsedTorrent) // objectMap will be updated when info event is emitted
} else if (infoHash && torrentObjMap[infoHash]) {
torrentObjMap[infoHash].tabClients.add(tabId)
}
return { ...state, torrentObjMap, torrentStateMap }
}
const saveAllFiles = (state: TorrentsState, infoHash: string) => {
webtorrentSaveAllFiles(infoHash)
return { ...state }
}
const defaultState: TorrentsState = { torrentStateMap: {}, torrentObjMap: {} }
export const webtorrentReducer = (
state: TorrentsState = defaultState,
action: any
) => {
// TODO: modify any to be actual action type
const payload = action.payload
switch (action.type) {
case tabTypes.types.TAB_UPDATED:
if (payload.changeInfo.url) {
state = tabUpdated(payload.tabId, payload.changeInfo.url, state)
}
break
case tabTypes.types.TAB_REMOVED:
state = tabRemoved(payload.tabId, state)
break
case tabTypes.types.TAB_RETRIEVED:
if (payload.tab.id && payload.tab.url) {
state = tabUpdated(payload.tab.id, payload.tab.url, state)
}
break
case torrentTypes.types.WEBTORRENT_PROGRESS_UPDATED:
state = updateProgress(state, payload.torrent)
break
case torrentTypes.types.WEBTORRENT_INFO_UPDATED:
state = updateInfo(state, payload.torrent)
break
case torrentTypes.types.WEBTORRENT_SERVER_UPDATED:
state = updateServer(state, payload.torrent, payload.serverURL)
break
case torrentTypes.types.WEBTORRENT_START_TORRENT:
state = startTorrent(payload.torrentId, payload.tabId, state)
break
case torrentTypes.types.WEBTORRENT_STOP_DOWNLOAD:
state = stopDownload(payload.tabId, state)
break
case torrentTypes.types.WEBTORRENT_TORRENT_PARSED:
state = torrentParsed(
payload.torrentId,
payload.tabId,
payload.infoHash,
payload.errorMsg,
payload.parsedTorrent,
state
)
break
case torrentTypes.types.WEBTORRENT_SAVE_ALL_FILES:
state = saveAllFiles(state, payload.infoHash)
break
}
return state
}
@@ -1,16 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/. */
import { createStore } from 'redux'
import { wrapStore } from 'webext-redux'
import reducers from './reducers'
const store = createStore(reducers)
wrapStore(store, {
portName: 'WEBTORRENT'
})
export default store
@@ -1,149 +0,0 @@
// Copyright (c) 2024 The Brave Authors. All rights reserved.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
const WebTorrent = require('webtorrent')
import type * as TWebTorrent from 'webtorrent'
import { addTorrentEvents, removeTorrentEvents } from './events/torrentEvents'
import { addWebtorrentEvents } from './events/webtorrentEvents'
import { AddressInfo } from 'net'
import { Instance } from 'parse-torrent'
import { basename, extname } from 'path'
import * as JSZip from 'jszip'
let webTorrent: TWebTorrent.Instance | undefined
let servers: { [key: string]: any } = {}
export const getWebTorrent = (): TWebTorrent.Instance => {
if (!webTorrent) {
webTorrent = new WebTorrent({ tracker: { wrtc: false } })
addWebtorrentEvents(webTorrent!)
}
return webTorrent!
}
export const createServer = (
torrent: TWebTorrent.Torrent,
cb: (serverURL: string) => void
) => {
if (!torrent.infoHash) return // torrent is not ready
const opts = {
// Only allow requests from this origin ('chrome-extension://...) so
// websites cannot violate same-origin policy by reading contents of
// active torrents.
origin: window.location.origin,
// Use hostname option to mitigate DNS rebinding
// Ref: https://github.com/brave/browser-laptop/issues/12616
hostname: '127.0.0.1'
}
const server = torrent.createServer(opts)
if (!server) return
try {
server.listen(0, '127.0.0.1', undefined, () => {
// Explicitly cast server.address() to AddressInfo to access its
// properties. It's safe to cast here because the only possible type of
// server.address() here is AddressInfo since pipe name (as string) is
// not supported in chrome-net.
const addrInfo = server.address() as AddressInfo
servers[torrent.infoHash] = server
cb('http://' + addrInfo.address + ':' + addrInfo.port.toString())
})
} catch (error) {
console.log('server listen error: ', error)
}
}
export const addTorrent = (torrentId: string | Instance) => {
const client = getWebTorrent()
const torrent = client.add(torrentId)
addTorrentEvents(torrent)
}
export const findTorrent = (infoHash: string) => {
return getWebTorrent().torrents.find(
(torrent) => torrent.infoHash === infoHash
)
}
const maybeDestroyWebTorrent = () => {
if (!webTorrent || webTorrent.torrents.length !== 0) return
webTorrent.destroy()
webTorrent = undefined
}
export const delTorrent = (infoHash: string) => {
const torrent = findTorrent(infoHash)
if (torrent) {
removeTorrentEvents(torrent)
torrent.destroy()
}
if (servers[infoHash]) {
servers[infoHash].close()
delete servers[infoHash]
}
maybeDestroyWebTorrent()
}
export const saveAllFiles = (infoHash: string) => {
const torrent = findTorrent(infoHash)
if (!torrent || !torrent.name || !torrent.files) return
const files: TWebTorrent.TorrentFile[] = torrent.files
let zip: any = new JSZip()
const zipFilename = basename(torrent.name, extname(torrent.name)) + '.zip'
const downloadBlob = (blob: Blob) => {
const url = URL.createObjectURL(blob)
chrome.downloads.download({
url: url,
filename: zipFilename,
saveAs: false,
conflictAction: 'uniquify'
})
}
const downloadZip = () => {
if (files.length > 1) {
// generate the zip relative to the torrent folder
zip = zip.folder(torrent.name)
}
zip.generateAsync({ type: 'blob' }).then(
(blob: Blob) => downloadBlob(blob),
(err: Error) => console.error(err)
)
}
const addFilesToZip = () => {
let addedFiles = 0
files.forEach((file) => {
file.getBlob((err, blob) => {
if (err) {
console.error(err)
} else {
// add file to zip
zip.file(file.path, blob)
}
addedFiles += 1
// start the download when all files have been added
if (addedFiles === files.length) {
downloadZip()
}
})
})
}
addFilesToZip()
}
@@ -1,12 +0,0 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>WebTorrent</title>
<script src="/extension/out/brave_webtorrent.bundle.js"></script>
</head>
<body>
<div id="root"></div>
</body>
</html>
@@ -1,68 +0,0 @@
// Copyright (c) 2024 The Brave Authors. All rights reserved.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
import * as React from 'react'
import { render } from 'react-dom'
import { Provider } from 'react-redux'
import { Store } from 'webext-redux'
import Theme from 'brave-ui/theme/brave-default'
import { createGlobalStyle, ThemeProvider } from 'styled-components'
// Components
import App from './components/app'
// Constants
import { ApplicationState } from './constants/webtorrentState'
import '$web-components/app.global.scss'
// This is a hack that's needed for lazy loading
// Basically we need the browser to restart the navigation, so we redirect first
// to brave_webtorrent2.html and have that rewrite the URL to
// brave_webtorrent.html
if (window.location.pathname === '/extension/brave_webtorrent2.html') {
window.location.href = window.location.href.replace(
'brave_webtorrent2.html',
'brave_webtorrent.html'
)
}
const GlobalStyle = createGlobalStyle`
body {
background: var(--background2);
}
`
const store: Store<ApplicationState> = new Store({
portName: 'WEBTORRENT'
})
// This pattern is described in the webext-redux docs. When the proxy store is
// ready, it doesn't necessarily have a value (and might be {}). If we want
// the same store value as the background page, we should wait for the first
// update and unsubscribe.
// https://github.com/tshaddix/webext-redux/wiki/Advanced-Usage#initializing-ui-components
const unsubscribe = store.subscribe(async () => {
unsubscribe()
try {
const tab: any = await new Promise((resolve) =>
chrome.tabs.getCurrent(resolve)
)
render(
<Provider store={store}>
<GlobalStyle />
<ThemeProvider theme={Theme}>
<App tabId={tab.id} />
</ThemeProvider>
</Provider>,
document.getElementById('root')
)
} catch (err) {
console.log('Problem mounting webtorrent', err)
}
})
@@ -1,12 +0,0 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>WebTorrent</title>
<script src="/extension/out/brave_webtorrent.bundle.js"></script>
</head>
<body>
<div id="root"></div>
</body>
</html>
@@ -1,82 +0,0 @@
// Copyright (c) 2024 The Brave Authors. All rights reserved.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
import * as React from 'react'
import { bindActionCreators, Dispatch } from 'redux'
import { connect } from 'react-redux'
// Components
import MediaViewer from './mediaViewer'
import TorrentViewer from './torrentViewer'
// Constants
import {
TorrentObj,
TorrentState,
ApplicationState,
getTorrentObj,
getTorrentState
} from '../constants/webtorrentState'
// Utils
import * as torrentActions from '../actions/webtorrent_actions'
interface Props {
torrentState: TorrentState
torrentObj?: TorrentObj
actions: any
}
// Exported for tests.
export function BraveWebTorrentPage({
actions,
torrentState,
torrentObj
}: Props) {
const name = torrentObj?.name ?? torrentState?.name
React.useEffect(() => {
document.title = name ? `${name} - WebTorrent` : 'WebTorrent'
}, [name])
if (!torrentState) return null
if (
torrentObj &&
typeof torrentState.ix === 'number' &&
torrentState.infoHash
) {
return (
<MediaViewer
torrent={torrentObj}
ix={torrentState.ix}
/>
)
}
return (
<TorrentViewer
actions={actions}
name={name}
torrentState={torrentState}
torrent={torrentObj}
/>
)
}
export const mapStateToProps = (
state: ApplicationState,
ownProps: { tabId: number }
) => {
return {
torrentState: getTorrentState(state.torrentsData, ownProps.tabId),
torrentObj: getTorrentObj(state.torrentsData, ownProps.tabId)
}
}
export const mapDispatchToProps = (dispatch: Dispatch) => ({
actions: bindActionCreators(torrentActions, dispatch)
})
export default connect(mapStateToProps, mapDispatchToProps)(BraveWebTorrentPage)
@@ -1,13 +0,0 @@
// Copyright (c) 2022 The Brave Authors. All rights reserved.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// you can obtain one at https://mozilla.org/MPL/2.0/.
import styled from 'styled-components'
export const Header = styled.h2`
all: unset;
font-weight: 600;
font-size: 24px;
color: var(--text2);
`
@@ -1,18 +0,0 @@
// Copyright (c) 2022 The Brave Authors. All rights reserved.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// you can obtain one at https://mozilla.org/MPL/2.0/.
import styled, { css } from 'styled-components'
export const Link = styled('a')<{ inactive?: boolean }>`
text-decoration: none;
color: var(--interactive2);
${p => p.inactive && css`
color: var(--text3);
:hover {
cursor: default;
}
`}
`
@@ -1,139 +0,0 @@
// Copyright (c) 2024 The Brave Authors. All rights reserved.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
import * as React from 'react'
import styled from 'styled-components'
// Constants
import { TorrentObj } from '../constants/webtorrentState'
import { getFileType, isMedia } from '../utils/fileType'
import Spinner from './spinner'
const getSelectedFile = (torrent: TorrentObj, ix: number) => torrent.files?.[ix]
const Container = styled.div`
video,
audio,
image-rendering,
object,
iframe,
img {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
max-height: 100%;
max-width: 100%;
margin: auto;
}
object,
iframe {
width: 100%;
height: 100%;
}
iframe {
border: 0;
}
`
const LoadingContainer = styled.div`
color: var(--text3);
margin-top: 40px;
display: flex;
gap: 8px;
justify-content: center;
align-items: center;
width: 100%;
`
interface Props {
torrent: TorrentObj
ix: number
}
const playMedia = (element: HTMLMediaElement) =>
element.play().catch((err) => console.error('Autoplay failed', err))
const setMediaElementRef = (element: HTMLMediaElement | null) => {
if (!element) return
if (element.readyState >= HTMLMediaElement.HAVE_CURRENT_DATA) {
playMedia(element)
return
}
element.addEventListener('loadeddata', () => playMedia(element), {
once: true
})
}
export default function MediaViewer({ torrent, ix }: Props) {
const file = getSelectedFile(torrent, ix)
const fileType = getFileType(file)
const fileURL = torrent.serverURL && torrent.serverURL + '/' + ix
const loading = !file || !fileURL
React.useEffect(() => {
document.body.style.backgroundColor = isMedia(fileType)
? 'rgb(0, 0, 0)'
: ''
// Reset background color when unmounted.
return () => {
document.body.style.backgroundColor = ''
}
}, [fileType])
return (
<Container>
{loading ? (
<LoadingContainer>
<Spinner />
Loading media...
</LoadingContainer>
) : (
<>
{fileType === 'video' && (
<video
id='video'
src={fileURL}
ref={setMediaElementRef}
controls
/>
)}
{fileType === 'audio' && (
<audio
id='audio'
src={fileURL}
ref={setMediaElementRef}
controls
/>
)}
{fileType === 'image' && (
<img
id='image'
src={fileURL}
/>
)}
{fileType === 'pdf' && (
<object
id='object'
type='application/pdf'
data={fileURL}
/>
)}
{fileType === 'iframe' && (
<iframe
id='iframe'
src={fileURL}
sandbox='allow-same-origin'
/>
)}
{fileType === 'unknown' && <div>Unsupported file type</div>}
</>
)}
</Container>
)
}
@@ -1,18 +0,0 @@
// Copyright (c) 2022 The Brave Authors. All rights reserved.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// you can obtain one at https://mozilla.org/MPL/2.0/.
import { LoaderIcon } from 'brave-ui/components/icons'
import * as React from 'react'
import styled from 'styled-components'
const Container = styled.div`
height: 32px;
width: 32px;
`
export default function Spinner () {
return <Container>
<LoaderIcon />
</Container>
}
@@ -1,176 +0,0 @@
// Copyright (c) 2024 The Brave Authors. All rights reserved.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
import { Button, Table } from 'brave-ui/components'
import { Cell, Row } from 'brave-ui/components/dataTables/table/index'
import * as prettierBytes from 'prettier-bytes'
import * as React from 'react'
import styled from 'styled-components'
import { File, TorrentObj } from '../constants/webtorrentState'
import { getFileType } from '../utils/fileType'
import { Header } from './header'
import { Link } from './link'
import Spinner from './spinner'
interface Props {
torrentId: string
torrent?: TorrentObj
onSaveAllFiles: () => void
}
const Container = styled.div`
display: flex;
flex-direction: column;
gap: 16px;
`
const HeaderRow = styled.div`
display: flex;
justify-content: space-between;
`
const FilesContainer = styled.div`
background: var(--background1);
border-radius: 8px;
padding: 16px;
box-shadow: 0px 0.5px 1.5px 0px rgb(0 0 0 / 15%);
td {
border: none;
color: var(--text1);
}
th {
border-top: none;
border-color: var(--divider1);
border-width: 2px;
color: var(--text3);
}
table {
margin: 0;
padding: 0;
}
`
const LoadingContainer = styled.div`
display: flex;
flex-direction: column;
`
const SaveButton = styled(Button)`
--button-main-color: var(--text1);
--button-main-color-hover: var(--text2);
`
const tableHeader: Cell[] = [
{
content: '#'
},
{
content: 'Name'
},
{
content: 'Save file'
},
{
content: 'Size'
}
]
const downloadFile = (url: string, filename: string) => {
chrome.downloads.download({
url,
filename
})
}
export default function TorrentFileList({
torrent,
torrentId,
onSaveAllFiles
}: Props) {
const rows = React.useMemo<Row[] | undefined>(
() =>
torrent?.files?.map((file: File, index: number) => ({
content: [
{
content: index + 1
},
{
content:
getFileType(file) !== 'unknown' ? (
<Link
target='_blank'
rel='noopener'
href={
torrentId +
(/^https?:/.test(torrentId) ? '#ix=' : '&ix=') +
index
}
>
{file.name}
</Link>
) : (
<span>{file.name}</span>
)
},
{
content: torrent.serverURL && (
<SaveButton
text='Save file'
level='secondary'
onClick={() =>
downloadFile(
`${torrent.serverURL}/${index}/${file.name}`,
file.name
)
}
/>
)
},
{
content: prettierBytes(file.length)
}
]
})),
[torrent?.files, torrentId]
)
const saveAllFiles = () => {
if (!torrent?.serverURL || !torrent?.files || torrent?.progress !== 1) {
return
}
onSaveAllFiles()
}
return (
<Container>
<HeaderRow>
<Header>Files</Header>
<Button
onClick={saveAllFiles}
disabled={torrent?.progress !== 1}
text='Save all files'
/>
</HeaderRow>
<FilesContainer>
<Table
header={tableHeader}
rows={rows}
>
{torrent && !torrent.files ? (
<LoadingContainer>
<Spinner />
Loading the torrent file list
</LoadingContainer>
) : (
'Click "Start Torrent" to begin your download.'
)}
</Table>
</FilesContainer>
</Container>
)
}
@@ -1,100 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/. */
import * as prettierBytes from 'prettier-bytes'
import * as React from 'react'
// Constants
import styled from 'styled-components'
import { TorrentObj } from '../constants/webtorrentState'
import { Header } from './header'
const Container = styled.div`
display: flex;
flex-direction: column;
gap: 16px;
`
const StatsContainer = styled.div`
display: flex;
flex-wrap: wrap;
gap: 16px;
padding: 16px;
border-radius: 8px;
background: var(--background1);
box-shadow: 0px 0.5px 1.5px 0px rgb(0 0 0 / 15%);
font-size: 16px;
font-weight: 400;
line-height: 24px;
`
const StatusText = styled.span`
font-weight: 600;
`
const StatsDivider = () => <span></span>
interface Props {
torrent?: TorrentObj
errorMsg?: string
}
function Eta ({ torrent }: { torrent: TorrentObj }) {
// Zero download speed
if (torrent.timeRemaining === 0 || torrent.timeRemaining === Infinity) return null
// Already done
if (torrent.downloaded === torrent.length) return null
const rawEta = torrent.timeRemaining / 1000
const hours = Math.floor(rawEta / 3600) % 24
const minutes = Math.floor(rawEta / 60) % 60
const seconds = Math.floor(rawEta % 60)
// Only display hours and minutes if they are greater than 0 but always
// display minutes if hours is being displayed
const hoursStr = hours ? hours + 'h' : ''
const minutesStr = hours || minutes ? minutes + 'm' : ''
const secondsStr = seconds + 's'
return <>
<StatsDivider />
<span>
{hoursStr} {minutesStr} {secondsStr} remaining
</span>
</>
}
export default function TorrentStatus ({ torrent, errorMsg }: Props) {
if (errorMsg) return <div>{errorMsg}</div>
if (!torrent) return null
const downloaded = prettierBytes(torrent.downloaded)
const total = prettierBytes(torrent.length)
return <Container>
<Header>Torrent stats</Header>
<StatsContainer>
<StatusText>{torrent.progress < 1 ? 'Downloading' : 'Seeding'}</StatusText>
<StatsDivider/>
<span>{torrent.progress < 1 ? (torrent.progress * 100).toFixed(1) : 100}%</span>
<StatsDivider/>
{torrent.downloadSpeed !== 0 && <>
<span> {prettierBytes(torrent.downloadSpeed)}/s</span>
<StatsDivider/>
</>}
{torrent.uploadSpeed !== 0 && <>
<span> {prettierBytes(torrent.uploadSpeed)}/s</span>
<StatsDivider/>
</>}
<span>{downloaded}{downloaded !== total && ` / ${total}`}</span>
<StatsDivider/>
<span>{torrent.numPeers} {torrent.numPeers === 1 ? 'peer' : 'peers'}</span>
<Eta torrent={torrent}/>
</StatsContainer>
</Container>
}
@@ -1,75 +0,0 @@
// Copyright (c) 2024 The Brave Authors. All rights reserved.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
import * as React from 'react'
// Assets
// Components
import TorrentFileList from './torrentFileList'
import TorrentStatus from './torrentStatus'
import TorrentViewerFooter from './torrentViewerFooter'
import TorrentViewerHeader from './torrentViewerHeader'
// Constants
import styled from 'styled-components'
import { TorrentObj, TorrentState } from '../constants/webtorrentState'
interface Props {
actions: any
name?: string | string[]
torrent?: TorrentObj
torrentState: TorrentState
}
const StyledTorrentViewer = styled.div`
display: flex;
flex-direction: column;
gap: 40px;
min-height: 100%;
padding: 50px;
font-family: Muli, sans-serif;
max-width: 1280px;
margin: 0 auto;
color: var(--text1);
button > div {
font-weight: 600;
}
`
export default function TorrentViewer({
actions,
name,
torrent,
torrentState
}: Props) {
const { torrentId, tabId, errorMsg, infoHash } = torrentState
return (
<StyledTorrentViewer>
<TorrentViewerHeader
name={name}
torrent={torrent}
torrentId={torrentId}
tabId={tabId}
onStartTorrent={actions.startTorrent}
onStopDownload={actions.stopDownload}
/>
<TorrentStatus
torrent={torrent}
errorMsg={errorMsg}
/>
<TorrentFileList
torrentId={torrentId}
torrent={torrent}
onSaveAllFiles={() => actions.saveAllFiles(infoHash)}
/>
<TorrentViewerFooter torrent={torrent} />
</StyledTorrentViewer>
)
}
@@ -1,36 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/. */
import { Anchor } from 'brave-ui/old'
import * as React from 'react'
// Constants
import styled from 'styled-components'
import { TorrentObj } from '../constants/webtorrentState'
interface Props {
torrent?: TorrentObj
}
const FooterNotice = styled.div`
padding: 18px 0;
color: var(--text3);
`
export default function TorrentViewerFooter ({ torrent }: Props) {
return torrent
? <Anchor
href='https://webtorrent.io'
text='Powered By WebTorrent'
target='_blank' />
: <FooterNotice>
<b>Privacy Warning:</b> When you click "Start Torrent" Brave will begin
downloading pieces of the torrent file from other users and uploading to
them in turn. This action will share that you're downloading this file.
Others may be able to see what you're downloading and/or determine your
public IP address. The download may bypass your proxy settings.
<br /><br />
The WebTorrent extension can be disabled from Brave settings.
</FooterNotice>
}
@@ -1,127 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/. */
import { Button } from 'brave-ui/components'
import * as React from 'react'
// Constants
import styled from 'styled-components'
import { TorrentObj } from '../constants/webtorrentState'
interface Props {
name?: string | string[]
torrent?: TorrentObj
torrentId: string
tabId: number
onStartTorrent: (torrentId: string, tabId: number) => void
onStopDownload: (tabId: number) => void
}
const remoteProtocols = ['http:', 'https:', 'ftp:', 'sftp:', 'ws:', 'wss:']
const HeaderText = styled.h1`
all: unset;
font-weight: 600;
font-size: 28px;
line-height: 38px;
`
const HeaderRow = styled.div`
display: flex;
justify-content: space-between;
`
const ButtonsContainer = styled.div`
display: flex;
gap: 8px;
--button-main-color: var(--interactive2);
`
export default function TorrentHeaderViewer ({ torrent, torrentId, name, tabId, onStartTorrent, onStopDownload }: Props) {
name = typeof name === 'object'
? name[0]
: name
const title = name || 'Loading torrent information...'
const mainButtonText = torrent ? 'Stop Torrent' : 'Start Torrent'
const copyButtonText = torrentId.startsWith('magnet:')
? 'Copy Magnet Link'
: 'Save .torrent File'
const onCopyClick = async () => {
if (torrentId.startsWith('magnet:')) {
try {
await navigator.clipboard.writeText(torrentId)
console.log('Copy succeeded')
} catch (e) {
console.log('Copy failed')
}
} else {
const downloadListener = (item: chrome.downloads.DownloadItem) => {
chrome.downloads.onDeterminingFilename.removeListener(downloadListener)
if (!item || !item.url || item.url !== torrentId) {
// Only listen for downloads initiated by Webtorrent.
return
}
const url = new URL(item.finalUrl || item.url)
if (!url || !remoteProtocols.includes(url.protocol) ||
url.hostname === '127.0.0.1') {
// Non-remote files are trusted.
return
}
if (!item.filename || !item.filename.endsWith('.torrent')) {
try {
chrome.downloads.cancel(item.id, () => {
const msg = 'Error: file is not a .torrent.'
// By default, alert() shows up on every tab that has loaded webtorrent.
// We only want it to show on the current tab.
chrome.tabs.query({
active: true,
lastFocusedWindow: true
}, (tabs) => {
const tab = tabs[0]
if (tab && typeof tab.id === 'number') {
chrome.tabs.executeScript(tab.id, {
code: `alert('${msg}')`
}, () => {
if (chrome.runtime.lastError) {
console.error('tabs.executeScript failed: ' + chrome.runtime.lastError.message)
}
})
return
}
alert(msg)
})
})
} catch (e) {
console.error(e)
}
}
}
// Listen for malicious files pretending to be .torrents
chrome.downloads.onDeterminingFilename.addListener(downloadListener)
const a = document.createElement('a')
a.download = ''
a.href = torrentId
a.click()
}
}
return <HeaderRow>
<HeaderText>{title}</HeaderText>
<ButtonsContainer>
<Button
type='accent'
level={!torrent ? 'primary' : 'secondary'}
text={mainButtonText}
onClick={() => torrent ? onStopDownload(tabId) : onStartTorrent(torrentId, tabId)} />
<Button
type='accent'
level='secondary'
text={copyButtonText}
onClick={onCopyClick} />
</ButtonsContainer>
</HeaderRow>
}
@@ -1,9 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/. */
export const enum types {
TAB_UPDATED = '@@tab/TAB_UPDATED',
TAB_REMOVED = '@@tab/TAB_REMOVED',
TAB_RETRIEVED = '@@tab/TAB_RETRIEVED'
}
@@ -1,67 +0,0 @@
// Copyright (c) 2024 The Brave Authors. All rights reserved.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
export const getTorrentState = (state: TorrentsState, tabId: number) => {
return state.torrentStateMap[tabId]
}
export const getTorrentObj = (state: TorrentsState, tabId: number) => {
let torrent
const torrentState = getTorrentState(state, tabId)
if (torrentState && torrentState.infoHash) {
torrent = state.torrentObjMap[torrentState.infoHash]
}
return torrent
}
export interface ApplicationState {
torrentsData: TorrentsState
}
export interface TorrentsState {
torrentStateMap: TorrentStateMap
torrentObjMap: TorrentObjMap
}
export interface TorrentStateMap {
[key: number]: TorrentState // tabId as key
}
export interface TorrentObjMap {
[key: string]: TorrentObj // infoHash as key
}
export interface File {
name: string
length: number
path: string
}
export interface TorrentState {
tabId: number
torrentId: string
name?: string | string[]
infoHash?: string
errorMsg?: string
ix?: number | number[]
}
export interface TorrentObj {
name?: string
files?: File[]
serverURL?: string
timeRemaining: number
downloaded: number
uploaded: number
downloadSpeed: number
uploadSpeed: number
progress: number
ratio: number
numPeers: number
length: number
tabClients: Set<number>
}
@@ -1,13 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/. */
export const enum types {
WEBTORRENT_PROGRESS_UPDATED = '@@webtorrent/WEBTORRENT_PROGRESS_UPDATED',
WEBTORRENT_INFO_UPDATED = '@@webtorrent/WEBTORRENT_INFO_UPDATED',
WEBTORRENT_SERVER_UPDATED = '@@webtorrent/WEBTORRENT_SERVER_UPDATED',
WEBTORRENT_START_TORRENT = '@@webtorrent/WEBTORRENT_START_TORRENT',
WEBTORRENT_STOP_DOWNLOAD = '@@webtorrent/WEBTORRENT_STOP_DOWNLOAD',
WEBTORRENT_TORRENT_PARSED = '@@webtorrent/WEBTORRENT_TORRENT_PARSED',
WEBTORRENT_SAVE_ALL_FILES = '@@webtorrent/WEBTORRENT_SAVE_ALL_FILES'
}
@@ -1,31 +0,0 @@
{
"version": "1.0.0",
"name": "Brave WebTorrent",
"manifest_version": 2,
"description": "WebTorrent extension",
"background" : {
"scripts": ["extension/out/brave_webtorrent_background.bundle.js"],
"persistent": false
},
"permissions": [
"downloads",
"dns",
"tabs",
"webNavigation",
"<all_urls>" // without '<all_urls>' sometimes get CORS issues when fetching the torrent file
],
"sockets": {
"udp": {
"send": "*",
"bind": "*"
},
"tcp": {
"connect": "*"
},
"tcpServer": {
"listen": "*:*"
}
},
"content_security_policy": "frame-ancestors 'none'; default-src 'self'; connect-src 'self' http: https:; font-src 'self' data:; script-src 'self'; media-src 'self' http://127.0.0.1:*; form-action 'none'; style-src 'self' 'unsafe-inline'; img-src 'self' data: http://127.0.0.1:*; object-src 'self' http://127.0.0.1:*; frame-src 'self' http://127.0.0.1:*;",
"key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArfOx1MW/cb3YPNlmT37CuISYgRbtR1SIdgnx/cfTyXO/PuD1VVsQWLDmrZGDmYVCzZvP36t75uhpJH4IoXL58U16yhdXZeSlb0LKcgMZB6cMNyjznV4NTEeY+tLnwGaB1TVdkJgSlY09psyfvcdzQd8xz9CNE6CXDzEq8+uMSaoAyEJ3nP78yV33nBrMj3jbjTi1fr2QsrpoISql/pJ9Zr5V0QbK4wIqln20ly96KuAO5c1DM9z9VnoYFdirEZBfkT/4gB7pBfyd4ScoMhXuaa9w53N8Espu1bC0RGmaKB679rGQdaBTrEUGF+PNfsucjnyrsnup6GMVhc91CXTDjQIDAQAB"
}
@@ -1,68 +0,0 @@
// Copyright (c) 2022 The Brave Authors. All rights reserved.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// you can obtain one at https://mozilla.org/MPL/2.0/.
const SUPPORTED_VIDEO_EXTENSIONS = [
'm4v',
'mkv',
'mov',
'mp4',
'ogv',
'webm'
]
const SUPPORTED_AUDIO_EXTENSIONS = [
'aac',
'flac',
'm4a',
'm4b',
'm4p',
'mp3',
'oga',
'ogg',
'wav'
]
const SUPPORTED_IMAGE_EXTENSIONS = [
'bmp',
'gif',
'jpeg',
'jpg',
'png',
'svg'
]
const SUPPORTED_PDF_EXTENSIONS = [
'pdf'
]
const SUPPORTED_IFRAME_EXTENSIONS = [
'css',
'html',
'js',
'md',
'txt'
]
export type FileType = 'video' | 'audio' | 'image' | 'pdf' | 'iframe' | 'unknown'
export const mediaTypes: FileType[] = ['video', 'audio', 'image']
export const isMedia = (fileType: FileType) => mediaTypes.includes(fileType)
// Given 'foo.txt', returns 'txt'
// undefined or README return ''
export const getExtension = (filename?: string) => {
if (!filename) return ''
const ix = filename.lastIndexOf('.')
if (ix < 0) return ''
return filename.substring(ix + 1)
}
export const getFileType = (file?: { name: string }): FileType => {
const extension = getExtension(file?.name)
if (SUPPORTED_VIDEO_EXTENSIONS.includes(extension)) return 'video'
if (SUPPORTED_AUDIO_EXTENSIONS.includes(extension)) return 'audio'
if (SUPPORTED_IMAGE_EXTENSIONS.includes(extension)) return 'image'
if (SUPPORTED_PDF_EXTENSIONS.includes(extension)) return 'pdf'
if (SUPPORTED_IFRAME_EXTENSIONS.includes(extension)) return 'iframe'
return 'unknown'
}
-18
View File
@@ -1,18 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<grit latest_public_release="0" current_release="1">
<outputs>
<output filename="grit/brave_webtorrent_resources.h" type="rc_header">
<emit emit_type='prepend'></emit>
</output>
<output filename="brave_webtorrent_static.pak" type="data_package" />
<output filename="grit/brave_webtorrent_resources_map.cc" type="resource_file_map_source" />
<output filename="grit/brave_webtorrent_resources_map.h" type="resource_map_header" />
</outputs>
<release seq="1">
<includes>
<include name="IDR_BRAVE_WEBTORRENT" file="extension/manifest.json" resource_path="brave_webtorrent/extension/manifest.json" type="BINDATA" />
<include name="IDR_BRAVE_WEBTORRENT_HTML" file="extension/brave_webtorrent.html" resource_path="brave_webtorrent/extension/brave_webtorrent.html" type="BINDATA" />
<include name="IDR_BRAVE_WEBTORRENT2_HTML" file="extension/brave_webtorrent2.html" resource_path="brave_webtorrent/extension/brave_webtorrent2.html" type="BINDATA" />
</includes>
</release>
</grit>
@@ -1,87 +0,0 @@
// Copyright (c) 2019 The Brave Authors. All rights reserved.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
import * as React from 'react'
import { Meta } from '@storybook/react'
// Components
import TorrentViewer from '../extension/components/torrentViewer'
import { TorrentState } from '../extension/constants/webtorrentState'
// Storybook
const fullPageStoryStyles: object = {
width: '-webkit-fill-available',
height: '-webkit-fill-available'
}
// Storybook helpers
const FullPageStory = (props: React.PropsWithChildren) => (
<div style={fullPageStoryStyles}>{props.children}</div>
)
function consoleLog() {
console.log('Clicked something')
}
const sampleTorrent = {
name: 'Sample Torrent',
files: [
{
name: 'file1.jpg',
path: 'path/to/file1.jpg',
length: 400
},
{
name: 'file2.jpg',
path: 'path/to/file2.jpg',
length: 500
}
],
serverURL: 'brave://myfile',
timeRemaining: 42,
downloaded: 2000,
uploaded: 8000,
downloadSpeed: 200,
uploadSpeed: 200,
progress: 0,
ratio: 0,
numPeers: 4000,
length: 4500,
tabClients: new Set([1, 2, 4, 5])
}
const torrentState: TorrentState = {
tabId: 1,
torrentId: 'id'
}
export default {
title: 'WebTorrent',
decorators: (Story) => (
<FullPageStory>
<Story />
</FullPageStory>
)
} as Meta<typeof TorrentViewer>
export const Page = {
render: () => (
<TorrentViewer
actions={consoleLog}
name={'Fake Torrent with really long title'}
torrentState={torrentState}
/>
)
}
export const PageWithTorrent = {
render: () => (
<TorrentViewer
actions={consoleLog}
torrent={sampleTorrent}
name={'Sample Torrent Name'}
torrentState={torrentState}
/>
)
}
-1
View File
@@ -26,7 +26,6 @@ brave_common_web_compile_inputs = [
rebase_path("../definitions/rewardsExtensions.d.ts"),
rebase_path("../definitions/throttleit.d.ts"),
rebase_path("../definitions/torInternals.d.ts"),
rebase_path("../definitions/webtorrent.d.ts"),
rebase_path("../definitions/welcome.d.ts"),
# webpack config changes warrant a re-build of all webpack builds
-4
View File
@@ -27,10 +27,6 @@ inline constexpr char kDisableBraveExtension[] = "disable-brave-extension";
// This switch disables update module(Sparkle).
inline constexpr char kDisableBraveUpdate[] = "disable-brave-update";
// Allows disabling the WebTorrent extension.
inline constexpr char kDisableWebTorrentExtension[] =
"disable-webtorrent-extension";
// Allows disabling the Wayback Machine extension.
inline constexpr char kDisableBraveWaybackMachineExtension[] =
"disable-brave-wayback-machine-extension";
-20
View File
@@ -1,20 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/. */
/// <reference path="../../node_modules/@types/webtorrent/index.d.ts" />
import { Server } from 'http'
interface CreateServerOpts {
origin: string
hostname: string
}
declare namespace WebTorrent {
interface Torrent extends NodeJS.EventEmitter {
createServer (opts?: CreateServerOpts): Server
}
}
export = WebTorrent
@@ -786,10 +786,6 @@
<message name="IDS_BRAVE_WALLET_DOWNLOADING" desc="">Downloading Component...</message>
<message name="IDS_BRAVE_WALLET_DISCLOSURE_CONFIRM" desc="">I understand</message>
<message name="IDS_PAGE_INFO_BRAVE_WEBTORRENT" desc="The message showed to the user in the HTTP info bubble view when viewing a webtorrent: page">
You're viewing a WebTorrent page
</message>
<message name="IDS_TEST_STRING_FOR_PLACEHOLDERS" desc="Only for test purpose. Don't need to translate">
Test string for <ph name="PART_ONE">$1</ph>place holders<ph name="PART_ONE_END">$2</ph>. <ph name="PART_TWO">$3</ph>Learn more<ph name="PART_TWO_END">$4</ph>
</message>
@@ -1,51 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/. */
import { types } from '../../../brave_webtorrent/extension/constants/tab_types'
import * as actions from '../../../brave_webtorrent/extension/actions/tab_actions'
const tab: chrome.tabs.Tab = {
id: 1,
index: 1,
pinned: false,
highlighted: false,
windowId: 1,
active: true,
incognito: false,
selected: false,
discarded: false,
autoDiscardable: false
}
const changeInfo: chrome.tabs.TabChangeInfo = {
url: 'https://test.com'
}
const tabId: number = 1
describe('tab_actions', () => {
it('tabUpdated', () => {
expect(actions.tabUpdated(tabId, changeInfo)).toEqual({
type: types.TAB_UPDATED,
meta: undefined,
payload: { tabId, changeInfo }
})
})
it('tabRemoved', () => {
expect(actions.tabRemoved(tabId)).toEqual({
type: types.TAB_REMOVED,
meta: undefined,
payload: { tabId }
})
})
it('tabRetrieved', () => {
expect(actions.tabRetrieved(tab)).toEqual({
type: types.TAB_RETRIEVED,
meta: undefined,
payload: { tab }
})
})
})

Some files were not shown because too many files have changed in this diff Show More