Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Implement Tor client updater as component extension #316

Merged
merged 4 commits into from
Aug 9, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions browser/brave_browser_process_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "base/threading/sequenced_task_runner_handle.h"
#include "brave/browser/component_updater/brave_component_updater_configurator.h"
#include "brave/browser/brave_stats_updater.h"
#include "brave/browser/extensions/brave_tor_client_updater.h"
#include "brave/components/brave_shields/browser/ad_block_service.h"
#include "brave/components/brave_shields/browser/ad_block_regional_service.h"
#include "brave/components/brave_shields/browser/https_everywhere_service.h"
Expand Down Expand Up @@ -119,3 +120,12 @@ BraveBrowserProcessImpl::https_everywhere_service() {
brave_shields::HTTPSEverywhereServiceFactory();
return https_everywhere_service_.get();
}

extensions::BraveTorClientUpdater*
BraveBrowserProcessImpl::tor_client_updater() {
if (tor_client_updater_)
return tor_client_updater_.get();

tor_client_updater_ = extensions::BraveTorClientUpdaterFactory();
return tor_client_updater_.get();
}
8 changes: 7 additions & 1 deletion browser/brave_browser_process_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ class HTTPSEverywhereService;
class TrackingProtectionService;
}

namespace extensions {
class BraveTorClientUpdater;
}

class BraveBrowserProcessImpl : public BrowserProcessImpl {
public:
BraveBrowserProcessImpl(base::SequencedTaskRunner* local_state_task_runner);
Expand All @@ -31,6 +35,7 @@ class BraveBrowserProcessImpl : public BrowserProcessImpl {
brave_shields::AdBlockRegionalService* ad_block_regional_service();
brave_shields::TrackingProtectionService* tracking_protection_service();
brave_shields::HTTPSEverywhereService* https_everywhere_service();
extensions::BraveTorClientUpdater* tor_client_updater();

private:
std::unique_ptr<brave_shields::AdBlockService> ad_block_service_;
Expand All @@ -41,9 +46,10 @@ class BraveBrowserProcessImpl : public BrowserProcessImpl {
std::unique_ptr<brave_shields::HTTPSEverywhereService>
https_everywhere_service_;
std::unique_ptr<brave::BraveStatsUpdater> brave_stats_updater_;
std::unique_ptr<extensions::BraveTorClientUpdater> tor_client_updater_;

component_updater::ComponentUpdateService* component_updater(
std::unique_ptr<component_updater::ComponentUpdateService> &,
std::unique_ptr<component_updater::ComponentUpdateService>&,
bool use_brave_server);
std::unique_ptr<component_updater::ComponentUpdateService>
google_component_updater_;
Expand Down
4 changes: 4 additions & 0 deletions browser/extensions/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ source_set("extensions") {
"api/brave_shields_api.h",
"api/content_settings/brave_content_settings_store.cc",
"api/content_settings/brave_content_settings_store.h",
"brave_component_extension.cc",
"brave_component_extension.h",
"brave_component_extension_resource_manager.cc",
"brave_component_extension_resource_manager.h",
"brave_component_loader.cc",
Expand All @@ -14,6 +16,8 @@ source_set("extensions") {
"brave_extension_management.h",
"brave_extension_provider.cc",
"brave_extension_provider.h",
"brave_tor_client_updater.cc",
"brave_tor_client_updater.h",
]

deps = [
Expand Down
61 changes: 61 additions & 0 deletions browser/extensions/brave_component_extension.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/* 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_component_extension.h"

#include <string>

#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback.h"
#include "brave/browser/component_updater/brave_component_installer.h"
#include "chrome/browser/browser_process.h"

void ComponentsUI::OnDemandUpdate(
component_updater::ComponentUpdateService* cus,
const std::string& component_id) {
cus->GetOnDemandUpdater().OnDemandUpdate(
component_id, component_updater::OnDemandUpdater::Priority::FOREGROUND,
component_updater::Callback());
}

BraveComponentExtension::BraveComponentExtension() {
}

BraveComponentExtension::~BraveComponentExtension() {
}

void BraveComponentExtension::Register(
const std::string& component_name,
const std::string& component_id,
const std::string& component_base64_public_key) {
component_name_ = component_name;
component_id_ = component_id;
component_base64_public_key_ = component_base64_public_key;

base::Closure registered_callback =
base::Bind(&BraveComponentExtension::OnComponentRegistered,
base::Unretained(this), component_id_);
ReadyCallback ready_callback =
base::Bind(&BraveComponentExtension::OnComponentReady,
base::Unretained(this), component_id_);
brave::RegisterComponent(g_browser_process->component_updater(),
component_name_, component_base64_public_key_,
registered_callback, ready_callback);
}

// static
bool BraveComponentExtension::Unregister(const std::string& component_id) {
return g_browser_process->component_updater()->UnregisterComponent(
component_id);
}

void BraveComponentExtension::OnComponentRegistered(const std::string& component_id) {
OnDemandUpdate(g_browser_process->component_updater(), component_id);
}

void BraveComponentExtension::OnComponentReady(
const std::string& component_id,
const base::FilePath& install_dir) {
}
40 changes: 40 additions & 0 deletions browser/extensions/brave_component_extension.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/* 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_COMPONENT_EXTENSION_H_
#define BRAVE_BROWSER_EXTENSIONS_BRAVE_COMPONENT_EXTENSION_H_

#include "base/files/file_path.h"
#include "components/component_updater/component_updater_service.h"

// Just used to give access to OnDemandUpdater since it's private.
// Chromium has ComponentsUI which is a friend class, so we just
// do this hack here to gain access.
class ComponentsUI {
public:
void OnDemandUpdate(component_updater::ComponentUpdateService* cus,
const std::string& component_id);
};

class BraveComponentExtension : public ComponentsUI {
public:
BraveComponentExtension();
virtual ~BraveComponentExtension();
void Register(const std::string& component_name,
const std::string& component_id,
const std::string& component_base64_public_key);
static bool Unregister(const std::string& component_id);

protected:
virtual void OnComponentRegistered(const std::string& component_id);
virtual void OnComponentReady(const std::string& component_id,
const base::FilePath& install_dir);

private:
std::string component_name_;
std::string component_id_;
std::string component_base64_public_key_;
};

#endif // BRAVE_BROWSER_EXTENSIONS_BRAVE_COMPONENT_EXTENSION_H_
10 changes: 10 additions & 0 deletions browser/extensions/brave_extension_management.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
#include "brave/browser/extensions/brave_extension_management.h"

#include "base/command_line.h"
#include "brave/browser/brave_browser_process_impl.h"
#include "brave/common/brave_switches.h"
#include "brave/common/extensions/extension_constants.h"
#include "brave/browser/extensions/brave_extension_provider.h"
#include "brave/browser/extensions/brave_tor_client_updater.h"
#include "chrome/browser/extensions/external_policy_loader.h"
#include "extensions/common/extension_urls.h"

Expand All @@ -24,6 +26,7 @@ BraveExtensionManagement::BraveExtensionManagement(
if (!command_line.HasSwitch(switches::kDisablePDFJSExtension)) {
RegisterForceInstalledExtensions();
}
RegisterBraveExtensions();
}

BraveExtensionManagement::~BraveExtensionManagement() {
Expand All @@ -37,4 +40,11 @@ void BraveExtensionManagement::RegisterForceInstalledExtensions() {
UpdateForcedExtensions(&forced_list_pref);
}

void BraveExtensionManagement::RegisterBraveExtensions() {
const base::CommandLine& command_line =
*base::CommandLine::ForCurrentProcess();
if (!command_line.HasSwitch(switches::kDisableTorClientUpdaterExtension))
g_brave_browser_process->tor_client_updater()->Register();
Copy link
Collaborator

Choose a reason for hiding this comment

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

do we need this in BraveBrowserProcess? Seems like it could just live here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

My thinking here was that BraveBrowserProcess would be the owner of long-lived services like the Tor client updater and then we'd just access it here via its getter so that we can register the extension on startup.

Are you suggesting to move the Register function into BraveExtensionManagement (or even the entire updater)? I haven't followed the code paths all the way through, but it seems like that could work. My only concerns would be that the registration happens at the correct time at startup (I definitely had a few issues with this before I settled on having BraveBrowserProcess own them) and that the updaters are easily accessible to other parts of the code.

Copy link
Collaborator

Choose a reason for hiding this comment

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

the tor client updater isn't a long-lived service, the component updater is the long-lived service and you are just registering things to be updated by it

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think maybe there is some confusion here because of the naming. I would use the WidevineCDMComponentInstaller as an example for this

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK, I see what you're saying about component updater. I did model this on some of the existing components (not specifically WidevineCDMComponentInstaller, but something similar). In our code, BraveComponentInstaller is fulfilling the same role as WidevineCDMComponentInstaller (i.e., it implements the installer policy and provides a register function).

It seems like making BraveComponentInstaller generic was a mistake; instead, it should be specific to this component and contain all of the logic that gets executed upon registration. Also, it seems like registration should occur in chrome_browser_main or somewhere similar. Is that the approach you're thinking of?

Copy link
Collaborator

Choose a reason for hiding this comment

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

probably in BraveBrowserMainExtraParts::PreMainMessageLoopRun

Copy link
Member

Choose a reason for hiding this comment

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

btw we'll want this opt in and not always registered. Installed first time switch is turned on in a private tab.
@cezaraugusto can you track this work and do the fix for the private tab UI? You could land a dead switch control any time.

}

} // namespace extensions
1 change: 1 addition & 0 deletions browser/extensions/brave_extension_management.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class BraveExtensionManagement : public ExtensionManagement {

private:
void RegisterForceInstalledExtensions();
void RegisterBraveExtensions();
DISALLOW_COPY_AND_ASSIGN(BraveExtensionManagement);
};

Expand Down
10 changes: 9 additions & 1 deletion browser/extensions/brave_extension_provider.cc
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ bool IsWhitelisted(const extensions::Extension* extension) {
"afalakplffnnnlkncjhbmahjfjhmlkal",
// Brave HTTPS Everywhere Updater
"oofiananboodjbbmdelgdommihjbkfag",
// Brave Tor Client Updater (Windows)
"cpoalefficncklhjfpglfiplenlpccdb",
// Brave Tor Client Updater (Mac)
"cldoidikboihgcjfkhdeidbpclkineef",
// Brave Tor Client Updater (Linux)
"biahpgbdmdkfgndcmfiipgcebobojjkp",
// Dashlane
"fdjamakpfbbddfjaooikfcpapjohcfmg",
// Enpass
Expand Down Expand Up @@ -72,7 +78,9 @@ bool IsWhitelisted(const extensions::Extension* extension) {
// Test ID: PDFJS
"kpbdcmcgkedhpbcpfndimofjnefgjidd",
// Test ID: Brave HTTPS Everywhere Updater
"bhlmpjhncoojbkemjkeppfahkglffilp"
"bhlmpjhncoojbkemjkeppfahkglffilp",
// Test ID: Brave Tor Client Updater
"ngicbhhaldfdgmjhilmnleppfpmkgbbk"
});
return std::find(whitelist.begin(), whitelist.end(),
extension->id()) != whitelist.end();
Expand Down
84 changes: 84 additions & 0 deletions browser/extensions/brave_tor_client_updater.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/* 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_tor_client_updater.h"

#include "base/files/file_enumerator.h"
#include "base/files/file_path.h"
#include "base/task_scheduler/post_task.h"
#include "third_party/re2/src/re2/re2.h"

namespace extensions {

std::string BraveTorClientUpdater::g_tor_client_component_id_(
kTorClientComponentId);
std::string BraveTorClientUpdater::g_tor_client_component_base64_public_key_(
kTorClientComponentBase64PublicKey);

BraveTorClientUpdater::BraveTorClientUpdater()
: task_runner_(
base::CreateSequencedTaskRunnerWithTraits({base::MayBlock()})),
registered_(false) {
}

BraveTorClientUpdater::~BraveTorClientUpdater() {
}

void BraveTorClientUpdater::Register() {
if (registered_)
return;

BraveComponentExtension::Register(kTorClientComponentName,
g_tor_client_component_id_,
g_tor_client_component_base64_public_key_);
registered_ = true;
}

base::FilePath BraveTorClientUpdater::GetExecutablePath() const {
return executable_path_;
}

void BraveTorClientUpdater::InitExecutablePath(
const base::FilePath& install_dir) {
base::FileEnumerator traversal(install_dir, false,
Copy link
Collaborator

Choose a reason for hiding this comment

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

This should be flagged for security audit. We shouldn't be using a wildcard here to find files, we need to look for a specific file and match the contents against a checksum cc @diracdeltas

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, good point. I implemented it like that because the Tor client embeds versioning and target platform information in its executable name (example: tor-0.3.3.8-win32-brave-5) and I didn't want to tightly couple the updater with a specific Tor client. I think one thing we can do here is to change the name of the Tor client to something a bit more generic when packaging it in the extension (e.g., brave-tor-client or something like that).

A checksum makes sense, but I think it would mean that we couldn't update the Tor client without also updating Brave. I think that's at least part of the problem the extension was meant to address.

cc: @riastradh-brave and @bbondy for any other thoughts here.

Copy link
Collaborator

Choose a reason for hiding this comment

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

we do validate the crx so the checksum can be included along with the exe

Copy link
Member

Choose a reason for hiding this comment

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

Thank you for flagging, I am assigning to @riastradh-brave for retroactive security review.

Copy link
Contributor

Choose a reason for hiding this comment

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

I would be perfectly fine with hard-coding a hash -- that's what we do currently. As I understand it, the only real specific motivation we have for doing a separate extension is to avoid antivirus software that is unhappy if Brave is bundled with a tor executable -- but even then, I'm not sure have any reports of antivirus software complaining that it's there; all the reports I'm aware of are complaints that it got executed.

Copy link
Contributor

Choose a reason for hiding this comment

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

Generally, we put out updates more frequently than tor does anyway.

Copy link
Contributor

@riastradh-brave riastradh-brave Aug 24, 2018

Choose a reason for hiding this comment

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

I see what's going on here. @emerick Can we just use a fixed pathname at a fixed location in the extension's install directory for the executable file? The only reason the file that is published via S3 has a different name is that we are publishing several different files, one for each platform.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@riastradh-brave Yeah, I'll update the packager to use a more generic name for the executable and then we'll just look specifically for that.

base::FileEnumerator::FILES,
FILE_PATH_LITERAL("tor-*"));
for (base::FilePath current = traversal.Next(); !current.empty();
current = traversal.Next()) {
base::FileEnumerator::FileInfo file_info = traversal.GetInfo();
if (RE2::FullMatch(file_info.GetName().MaybeAsASCII(),
"tor-\\d+\\.\\d+\\.\\d+\\.\\d+-\\w+-brave-\\d+")) {
executable_path_ = current;
return;
}
}

LOG(ERROR) << "Failed to locate Tor client executable in "
<< install_dir.value().c_str();
}

void BraveTorClientUpdater::OnComponentReady(
const std::string& component_id,
const base::FilePath& install_dir) {
GetTaskRunner()->PostTask(
FROM_HERE, base::Bind(&BraveTorClientUpdater::InitExecutablePath,
base::Unretained(this), install_dir));
}

// static
void BraveTorClientUpdater::SetComponentIdAndBase64PublicKeyForTest(
const std::string& component_id,
const std::string& component_base64_public_key) {
g_tor_client_component_id_ = component_id;
g_tor_client_component_base64_public_key_ = component_base64_public_key;
}

///////////////////////////////////////////////////////////////////////////////

// The Brave Tor client extension factory.
std::unique_ptr<BraveTorClientUpdater> BraveTorClientUpdaterFactory() {
return std::make_unique<BraveTorClientUpdater>();
}

} // namespace extensions
Loading