From 2cfb99e507b0ceab5e674da2cdabc4396061a3b4 Mon Sep 17 00:00:00 2001 From: Emerick Rogul Date: Thu, 23 Aug 2018 10:43:52 -0400 Subject: [PATCH 01/13] Add support for referral promos --- browser/BUILD.gn | 8 +- browser/brave_browser_process_impl.cc | 12 + browser/brave_browser_process_impl.h | 2 + browser/brave_local_state_prefs.cc | 2 + browser/referrals/BUILD.gn | 15 + browser/referrals/brave_referrals_service.cc | 477 +++++++++++++++++++ browser/referrals/brave_referrals_service.h | 88 ++++ common/network_constants.cc | 5 + common/network_constants.h | 6 +- common/pref_names.cc | 6 + common/pref_names.h | 6 + 11 files changed, 623 insertions(+), 4 deletions(-) create mode 100644 browser/referrals/BUILD.gn create mode 100644 browser/referrals/brave_referrals_service.cc create mode 100644 browser/referrals/brave_referrals_service.h diff --git a/browser/BUILD.gn b/browser/BUILD.gn index 34c351d9f150..de892705f51e 100644 --- a/browser/BUILD.gn +++ b/browser/BUILD.gn @@ -58,11 +58,12 @@ source_set("browser_process") { deps = [ ":version_info", "//base", - "//brave/components/brave_rewards/browser", + "//brave/browser/referrals", "//brave/browser/tor", + "//brave/common", + "//brave/components/brave_rewards/browser", "//brave/components/brave_shields/browser:brave_shields", "//brave/components/content_settings/core/browser", - "//brave/common", "//chrome/common", "//components/component_updater", "//components/prefs", @@ -113,11 +114,12 @@ source_set("browser") { "//brave/browser/resources:brave_extension_grit", "//chrome/browser", "extensions", - "tor", "net", "permissions", "profiles", + "referrals", "renderer_host", + "tor", "ui", "//ui/base", ] diff --git a/browser/brave_browser_process_impl.cc b/browser/brave_browser_process_impl.cc index d2ecf132b7df..45b0a88dc9d3 100644 --- a/browser/brave_browser_process_impl.cc +++ b/browser/brave_browser_process_impl.cc @@ -13,6 +13,7 @@ #include "brave/browser/extensions/brave_tor_client_updater.h" #include "brave/browser/profiles/brave_profile_manager.h" #include "brave/browser/profile_creation_monitor.h" +#include "brave/browser/referrals/brave_referrals_service.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" @@ -35,6 +36,17 @@ BraveBrowserProcessImpl::BraveBrowserProcessImpl(scoped_refptrPostDelayedTask( + FROM_HERE, + base::BindOnce( + [](brave::BraveReferralsService* referrals_service) { + referrals_service->Start(); + }, + base::Unretained(brave_referrals_service_.get())), + base::TimeDelta::FromSeconds(30)); + brave_stats_updater_ = brave::BraveStatsUpdaterFactory(local_state()); base::SequencedTaskRunnerHandle::Get()->PostDelayedTask( FROM_HERE, diff --git a/browser/brave_browser_process_impl.h b/browser/brave_browser_process_impl.h index c0ee9c228e1f..8c3b88619784 100644 --- a/browser/brave_browser_process_impl.h +++ b/browser/brave_browser_process_impl.h @@ -10,6 +10,7 @@ class ProfileCreationMonitor; namespace brave { +class BraveReferralsService; class BraveStatsUpdater; } @@ -51,6 +52,7 @@ class BraveBrowserProcessImpl : public BrowserProcessImpl { std::unique_ptr https_everywhere_service_; std::unique_ptr brave_stats_updater_; + std::unique_ptr brave_referrals_service_; std::unique_ptr tor_client_updater_; std::unique_ptr profile_creation_monitor_; diff --git a/browser/brave_local_state_prefs.cc b/browser/brave_local_state_prefs.cc index e2beffb72312..016976153112 100644 --- a/browser/brave_local_state_prefs.cc +++ b/browser/brave_local_state_prefs.cc @@ -6,6 +6,7 @@ #include "base/values.h" #include "brave/browser/brave_stats_updater.h" +#include "brave/browser/referrals/brave_referrals_service.h" #include "brave/browser/tor/tor_profile_service.h" #include "chrome/common/pref_names.h" #include "components/prefs/pref_registry_simple.h" @@ -14,6 +15,7 @@ namespace brave { void RegisterLocalStatePrefs(PrefRegistrySimple* registry) { RegisterPrefsForBraveStatsUpdater(registry); + RegisterPrefsForBraveReferralsService(registry); #if defined(OS_MACOSX) // Turn off super annoying 'Hold to quit' registry->SetDefaultPrefValue(prefs::kConfirmToQuitEnabled, diff --git a/browser/referrals/BUILD.gn b/browser/referrals/BUILD.gn new file mode 100644 index 000000000000..18f7d015bca3 --- /dev/null +++ b/browser/referrals/BUILD.gn @@ -0,0 +1,15 @@ +source_set("referrals") { + sources = [ + "brave_referrals_service.cc", + "brave_referrals_service.h", + ] + + deps = [ + "//base", + "//chrome/common", + "//components/prefs", + "//net", + "//services/network/public/cpp", + "//skia", + ] +} diff --git a/browser/referrals/brave_referrals_service.cc b/browser/referrals/brave_referrals_service.cc new file mode 100644 index 000000000000..2989185b9e45 --- /dev/null +++ b/browser/referrals/brave_referrals_service.cc @@ -0,0 +1,477 @@ +/* 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/referrals/brave_referrals_service.h" + +#include "base/environment.h" +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/json/json_reader.h" +#include "base/json/json_writer.h" +#include "base/path_service.h" +#include "base/strings/string_util.h" +#include "base/sys_info.h" +#include "base/task/post_task.h" +#include "base/values.h" +#include "brave/common/network_constants.h" +#include "brave/common/pref_names.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/first_run/first_run.h" +#include "chrome/browser/net/system_network_context_manager.h" +#include "chrome/browser/profiles/profile_manager.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/scoped_tabbed_browser_displayer.h" +#include "chrome/common/chrome_paths.h" +#include "components/prefs/pref_registry_simple.h" +#include "components/prefs/pref_service.h" +#include "net/base/load_flags.h" +#include "net/traffic_annotation/network_traffic_annotation.h" +#include "services/network/public/cpp/resource_request.h" +#include "services/network/public/cpp/simple_url_loader.h" + +// Fetch headers from the referral server once a day. +const int kFetchReferralHeadersFrequency = 60 * 60 * 24; + +// Maximum size of the referral server response in bytes. +const int kMaxReferralServerResponseSizeBytes = 1024 * 1024; + +namespace { + +std::string GetPlatformIdentifier() { +#if defined(OS_WIN) + if (base::SysInfo::OperatingSystemArchitecture() == "x86") + return "winia32"; + else + return "winx64"; +#elif defined(OS_MACOSX) + return "osx"; +#elif defined(OS_LINUX) + return "linux"; +#else + return std::string(); +#endif +} + +std::string BuildReferralEndpoint(const std::string& path) { + std::unique_ptr env(base::Environment::Create()); + std::string referral_server; + env->GetVar("BRAVE_REFERRALS_SERVER", &referral_server); + if (referral_server.empty()) + referral_server = kBraveReferralsServer; + return base::StringPrintf("https://%s%s", referral_server.c_str(), + path.c_str()); +} + +} // namespace + +namespace brave { + +BraveReferralsService::BraveReferralsService(PrefService* pref_service) + : initialized_(false), + task_runner_( + base::CreateSequencedTaskRunnerWithTraits({base::MayBlock()})), + pref_service_(pref_service), + weak_factory_(this) { +} + +BraveReferralsService::~BraveReferralsService() { +} + +void BraveReferralsService::Start() { + if (initialized_) + return; + + // Periodically fetch referral headers. + DCHECK(!fetch_referral_headers_timer_); + fetch_referral_headers_timer_ = std::make_unique(); + fetch_referral_headers_timer_->Start( + FROM_HERE, base::TimeDelta::FromSeconds(kFetchReferralHeadersFrequency), + this, &BraveReferralsService::OnFetchReferralHeadersTimerFired); + DCHECK(fetch_referral_headers_timer_->IsRunning()); + + std::string download_id = pref_service_->GetString(kReferralDownloadID); + if (download_id.empty() && first_run::IsChromeFirstRun()) + task_runner_->PostTaskAndReply( + FROM_HERE, + base::Bind(&BraveReferralsService::PerformFirstRunTasks, + base::Unretained(this)), + base::Bind(&BraveReferralsService::OnFirstRunTasksComplete, + weak_factory_.GetWeakPtr())); + else + FetchReferralHeaders(); + + // Check for referral finalization, if appropriate. + MaybeCheckForReferralFinalization(); + + initialized_ = true; +} + +void BraveReferralsService::Stop() { + fetch_referral_headers_timer_.reset(); + initialized_ = false; +} + +void BraveReferralsService::OnFetchReferralHeadersTimerFired() { + FetchReferralHeaders(); +} + +void BraveReferralsService::OnReferralHeadersLoadComplete( + std::unique_ptr response_body) { + int response_code = -1; + if (referral_headers_loader_->ResponseInfo() && + referral_headers_loader_->ResponseInfo()->headers) + response_code = + referral_headers_loader_->ResponseInfo()->headers->response_code(); + if (referral_headers_loader_->NetError() != net::OK || response_code < 200 || + response_code > 299) { + LOG(ERROR) << "Failed to fetch headers from referral server" + << ", error: " << referral_headers_loader_->NetError() + << ", response code: " << response_code + << ", payload: " << *response_body + << ", url: " << referral_headers_loader_->GetFinalURL().spec(); + return; + } + + std::unique_ptr root = base::JSONReader().ReadToValue(*response_body); + if (!root || !root->is_list()) { + LOG(ERROR) << "Failed to parse referral headers response"; + return; + } + pref_service_->Set(kReferralHeaders, *root); +} + +void BraveReferralsService::OnReferralInitLoadComplete( + std::unique_ptr response_body) { + int response_code = -1; + if (referral_init_loader_->ResponseInfo() && + referral_init_loader_->ResponseInfo()->headers) + response_code = + referral_init_loader_->ResponseInfo()->headers->response_code(); + if (referral_init_loader_->NetError() != net::OK || response_code < 200 || + response_code > 299) { + LOG(ERROR) << "Failed to initialize referral" + << ", error: " << referral_init_loader_->NetError() + << ", response code: " << response_code + << ", payload: " << *response_body + << ", url: " << referral_init_loader_->GetFinalURL().spec(); + return; + } + + std::unique_ptr root = base::JSONReader().ReadToValue(*response_body); + if (!root || !root->is_dict()) { + LOG(ERROR) << "Failed to parse referral initialization response"; + return; + } + if (!root->FindKey("download_id")) { + LOG(ERROR) << "Failed to locate download_id in referral initialization response" + << ", payload: " << *response_body; + return; + } + + const base::Value* offer_page_url = root->FindKey("offer_page_url"); + if (offer_page_url) { + chrome::ScopedTabbedBrowserDisplayer browser_displayer( + ProfileManager::GetLastUsedProfile()); + browser_displayer.browser()->OpenURL(content::OpenURLParams( + GURL(offer_page_url->GetString()), content::Referrer(), + WindowOpenDisposition::NEW_FOREGROUND_TAB, + ui::PAGE_TRANSITION_AUTO_TOPLEVEL, false)); + } + + if (root->FindKey("headers")) { + const base::Value* headers = root->FindKey("headers"); + pref_service_->Set(kReferralHeaders, *headers); + } + + const base::Value* download_id = root->FindKey("download_id"); + pref_service_->SetString(kReferralDownloadID, download_id->GetString()); + + const base::Value* referral_code = root->FindKey("referral_code"); + pref_service_->SetString(kReferralPromoCode, referral_code->GetString()); + + task_runner_->PostTask(FROM_HERE, + base::Bind(&BraveReferralsService::DeletePromoCodeFile, + base::Unretained(this))); +} + +void BraveReferralsService::OnReferralFinalizationCheckLoadComplete( + std::unique_ptr response_body) { + int response_code = -1; + if (referral_finalization_check_loader_->ResponseInfo() && + referral_finalization_check_loader_->ResponseInfo()->headers) + response_code = referral_finalization_check_loader_->ResponseInfo() + ->headers->response_code(); + if (referral_finalization_check_loader_->NetError() != net::OK || + response_code < 200 || response_code > 299) { + LOG(ERROR) << "Failed to perform referral finalization check" + << ", error: " << referral_finalization_check_loader_->NetError() + << ", response code: " << response_code + << ", payload: " << *response_body << ", url: " + << referral_finalization_check_loader_->GetFinalURL().spec(); + return; + } + + std::unique_ptr root = base::JSONReader().ReadToValue(*response_body); + if (!root || !root->is_list()) { + LOG(ERROR) << "Failed to parse referral finalization check response"; + return; + } + const base::Value* finalized = root->FindKey("finalized"); + if (!finalized->GetBool()) { + LOG(ERROR) << "Referral is not ready, please wait at least 30 days"; + return; + } + + // Now that referral is finalized, discard state so we don't check + // anymore. + pref_service_->SetTime(kReferralTimestamp, base::Time::Now()); + pref_service_->ClearPref(kReferralAttemptTimestamp); + pref_service_->ClearPref(kReferralAttemptCount); +} + +void BraveReferralsService::OnFirstRunTasksComplete() { + if (!promo_code_.empty()) + InitReferral(); +} + +void BraveReferralsService::PerformFirstRunTasks() { + ReadPromoCode(); +} + +base::FilePath BraveReferralsService::GetPromoCodeFileName() const { + base::FilePath user_data_dir; + base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); + return user_data_dir.AppendASCII("promoCode"); +} + +bool BraveReferralsService::ReadPromoCode() { + base::FilePath promo_code_file = GetPromoCodeFileName(); + if (!base::PathExists(promo_code_file)) { + return false; + } + if (!base::ReadFileToString(promo_code_file, &promo_code_)) { + LOG(ERROR) << "Failed to read referral promo code from " + << promo_code_file.value().c_str(); + return false; + } + base::TrimWhitespaceASCII(promo_code_, base::TRIM_ALL, &promo_code_); + if (promo_code_.empty()) { + LOG(ERROR) << "Promo code file " << promo_code_file.value().c_str() + << " is empty"; + return false; + } + return true; +} + +void BraveReferralsService::DeletePromoCodeFile() const { + base::FilePath promo_code_file = GetPromoCodeFileName(); + if (!base::DeleteFile(promo_code_file, false)) { + LOG(ERROR) << "Failed to delete referral promo code file " + << promo_code_file.value().c_str(); + return; + } +} + +void BraveReferralsService::MaybeCheckForReferralFinalization() { + std::string download_id = pref_service_->GetString(kReferralDownloadID); + if (download_id.empty()) { + return; + } + + // Only check for referral finalization after 30 days have elapsed + // since first run. + base::Time now = base::Time::Now(); + base::Time firstrun_timestamp = first_run::GetFirstRunSentinelCreationTime(); + if (now - firstrun_timestamp < base::TimeDelta::FromDays(30)) + return; + + // Only check for referral finalization 30 times, with a 24-hour + // wait between checks. + base::Time timestamp = pref_service_->GetTime(kReferralAttemptTimestamp); + int count = pref_service_->GetInteger(kReferralAttemptCount); + if (count >= 30) { + pref_service_->ClearPref(kReferralAttemptTimestamp); + pref_service_->ClearPref(kReferralAttemptCount); + pref_service_->ClearPref(kReferralDownloadID); + return; + } + + if (now - timestamp < base::TimeDelta::FromHours(24)) + return; + + pref_service_->SetTime(kReferralAttemptTimestamp, now); + pref_service_->SetInteger(kReferralAttemptCount, count + 1); + + CheckForReferralFinalization(); +} + +std::string BraveReferralsService::BuildReferralInitPayload() const { + std::unique_ptr env(base::Environment::Create()); + std::string api_key; + env->GetVar("REFERRAL_API_KEY", &api_key); + base::Value root(base::Value::Type::DICTIONARY); + root.SetKey("api_key", base::Value(api_key)); + root.SetKey("referral_code", base::Value(promo_code_)); + root.SetKey("platform", base::Value(GetPlatformIdentifier())); + std::string result; + base::JSONWriter::Write(root, &result); + return result; +} + +std::string BraveReferralsService::BuildReferralFinalizationCheckPayload() const { + std::unique_ptr env(base::Environment::Create()); + std::string api_key; + env->GetVar("REFERRAL_API_KEY", &api_key); + base::Value root(base::Value::Type::DICTIONARY); + root.SetKey("api_key", base::Value(api_key)); + root.SetKey("download_id", + base::Value(pref_service_->GetString(kReferralDownloadID))); + std::string result; + base::JSONWriter::Write(root, &result); + return result; +} + +void BraveReferralsService::FetchReferralHeaders() { + net::NetworkTrafficAnnotationTag traffic_annotation = + net::DefineNetworkTrafficAnnotation("brave_referral_headers_fetcher", R"( + semantics { + sender: + "Brave Referrals Service" + description: + "Fetches referral headers from Brave." + trigger: + "An update timer indicates that it's time to fetch referral headers." + data: "Brave referral headers." + destination: WEBSITE + } + policy { + cookies_allowed: NO + setting: + "This feature cannot be disabled by settings." + policy_exception_justification: + "Not implemented." + })"); + auto resource_request = std::make_unique(); + resource_request->url = + GURL(BuildReferralEndpoint(kBraveReferralsHeadersPath)); + resource_request->load_flags = + net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES | + net::LOAD_BYPASS_CACHE | net::LOAD_DISABLE_CACHE | + net::LOAD_DO_NOT_SEND_AUTH_DATA; + network::mojom::URLLoaderFactory* loader_factory = + g_browser_process->system_network_context_manager() + ->GetURLLoaderFactory(); + referral_headers_loader_ = network::SimpleURLLoader::Create( + std::move(resource_request), traffic_annotation); + referral_headers_loader_->SetAllowHttpErrorResults(true); + referral_headers_loader_->DownloadToString( + loader_factory, + base::BindOnce(&BraveReferralsService::OnReferralHeadersLoadComplete, + base::Unretained(this)), + kMaxReferralServerResponseSizeBytes); +} + +void BraveReferralsService::InitReferral() { + net::NetworkTrafficAnnotationTag traffic_annotation = + net::DefineNetworkTrafficAnnotation("brave_referral_initializer", R"( + semantics { + sender: + "Brave Referrals Service" + description: + "Validates the current referral offer with Brave, potentially " + "unlocking special features and/or services." + trigger: + "On startup, sends the current referral code to Brave." + data: "Brave referral metadata." + destination: WEBSITE + } + policy { + cookies_allowed: NO + setting: + "This feature cannot be disabled by settings." + policy_exception_justification: + "Not implemented." + })"); + auto resource_request = std::make_unique(); + resource_request->method = "PUT"; + resource_request->url = GURL(BuildReferralEndpoint(kBraveReferralsInitPath)); + resource_request->load_flags = + net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES | + net::LOAD_BYPASS_CACHE | net::LOAD_DISABLE_CACHE | + net::LOAD_DO_NOT_SEND_AUTH_DATA; + network::mojom::URLLoaderFactory* loader_factory = + g_browser_process->system_network_context_manager() + ->GetURLLoaderFactory(); + referral_init_loader_ = network::SimpleURLLoader::Create( + std::move(resource_request), traffic_annotation); + referral_init_loader_->SetAllowHttpErrorResults(true); + referral_init_loader_->AttachStringForUpload(BuildReferralInitPayload(), + "application/json"); + referral_init_loader_->DownloadToString( + loader_factory, + base::BindOnce(&BraveReferralsService::OnReferralInitLoadComplete, + base::Unretained(this)), + kMaxReferralServerResponseSizeBytes); +} + +void BraveReferralsService::CheckForReferralFinalization() { + net::NetworkTrafficAnnotationTag traffic_annotation = + net::DefineNetworkTrafficAnnotation("brave_referral_finalization_checker", R"( + semantics { + sender: + "Brave Referrals Service" + description: + "Fetches referral finalization data from Brave." + trigger: + "" + data: "Brave referral finalization status." + destination: WEBSITE + } + policy { + cookies_allowed: NO + setting: + "This feature cannot be disabled by settings." + policy_exception_justification: + "Not implemented." + })"); + auto resource_request = std::make_unique(); + resource_request->method = "PUT"; + resource_request->url = + GURL(BuildReferralEndpoint(kBraveReferralsActivityPath)); + resource_request->load_flags = + net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES | + net::LOAD_BYPASS_CACHE | net::LOAD_DISABLE_CACHE | + net::LOAD_DO_NOT_SEND_AUTH_DATA; + network::mojom::URLLoaderFactory* loader_factory = + g_browser_process->system_network_context_manager() + ->GetURLLoaderFactory(); + referral_finalization_check_loader_ = network::SimpleURLLoader::Create( + std::move(resource_request), traffic_annotation); + referral_finalization_check_loader_->SetAllowHttpErrorResults(true); + referral_finalization_check_loader_->AttachStringForUpload( + BuildReferralFinalizationCheckPayload(), "application/json"); + referral_finalization_check_loader_->DownloadToString( + loader_factory, + base::BindOnce( + &BraveReferralsService::OnReferralFinalizationCheckLoadComplete, + base::Unretained(this)), + kMaxReferralServerResponseSizeBytes); +} + +/////////////////////////////////////////////////////////////////////////////// + +std::unique_ptr BraveReferralsServiceFactory(PrefService* pref_service) { + return std::make_unique(pref_service); +} + +void RegisterPrefsForBraveReferralsService(PrefRegistrySimple* registry) { + registry->RegisterStringPref(kReferralPromoCode, std::string()); + registry->RegisterStringPref(kReferralDownloadID, std::string()); + registry->RegisterStringPref(kReferralTimestamp, std::string()); + registry->RegisterTimePref(kReferralAttemptTimestamp, base::Time()); + registry->RegisterIntegerPref(kReferralAttemptCount, 0); + registry->RegisterListPref(kReferralHeaders); +} + +} // namespace brave diff --git a/browser/referrals/brave_referrals_service.h b/browser/referrals/brave_referrals_service.h new file mode 100644 index 000000000000..01f23187a9b2 --- /dev/null +++ b/browser/referrals/brave_referrals_service.h @@ -0,0 +1,88 @@ +/* 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_BRAVE_REFERRALS_SERVICE_H_ +#define BRAVE_BROWSER_BRAVE_REFERRALS_SERVICE_H_ + +#include + +#include "base/files/file_path.h" +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "base/sequenced_task_runner.h" +#include "base/timer/timer.h" + +class PrefRegistrySimple; +class PrefService; + +namespace network { +class SimpleURLLoader; +} + +namespace brave { + +class BraveReferralsService { + public: + BraveReferralsService(PrefService* pref_service); + ~BraveReferralsService(); + + void Start(); + void Stop(); + + private: + void PerformFirstRunTasks(); + base::FilePath GetPromoCodeFileName() const; + bool ReadPromoCode(); + void DeletePromoCodeFile() const; + void MaybeCheckForReferralFinalization(); + void InitReferral(); + std::string BuildReferralInitPayload() const; + std::string BuildReferralFinalizationCheckPayload() const; + void FetchReferralHeaders(); + void CheckForReferralFinalization(); + + // Invoked from RepeatingTimer when referral headers timer fires. + void OnFetchReferralHeadersTimerFired(); + + // Invoked from SimpleURLLoader after download of referral headers + // is complete. + void OnReferralHeadersLoadComplete( + std::unique_ptr response_body); + + // Invoked from SimpleURLLoader after referral init load + // completes. + void OnReferralInitLoadComplete(std::unique_ptr response_body); + + // Invoked from SimpleURLLoader after referral finalization check + // load completes. + void OnReferralFinalizationCheckLoadComplete( + std::unique_ptr response_body); + + // Invoked after first run tasks are complete. + void OnFirstRunTasksComplete(); + + bool initialized_; + scoped_refptr task_runner_; + std::unique_ptr referral_headers_loader_; + std::unique_ptr referral_init_loader_; + std::unique_ptr referral_finalization_check_loader_; + std::unique_ptr fetch_referral_headers_timer_; + PrefService* pref_service_; + std::string promo_code_; + + base::WeakPtrFactory weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(BraveReferralsService); +}; + +// Creates the BraveReferralsService +std::unique_ptr BraveReferralsServiceFactory( + PrefService* pref_service); + +// Registers the preferences used by BraveReferralsService +void RegisterPrefsForBraveReferralsService(PrefRegistrySimple* registry); + +} // namespace brave + +#endif // BRAVE_BROWSER_BRAVE_REFERRALS_SERVICE_H_ diff --git a/common/network_constants.cc b/common/network_constants.cc index eec85688476e..1b5b1eee0e25 100644 --- a/common/network_constants.cc +++ b/common/network_constants.cc @@ -4,6 +4,11 @@ const char kBraveUpdatesExtensionsEndpoint[] = "https://go-updater.brave.com/ext // For debgugging: // const char kBraveUpdatesExtensionsEndpoint[] = "http://localhost:8192/extensions"; +const char kBraveReferralsServer[] = "laptop-updates.brave.com"; +const char kBraveReferralsHeadersPath[] = "/promo/custom-headers"; +const char kBraveReferralsInitPath[] = "/promo/initialize/nonua"; +const char kBraveReferralsActivityPath[] = "/promo/activity"; + const char kEmptyDataURI[] = "data:application/javascript;base64,MA=="; const char kJSDataURLPrefix[] = "data:application/javascript;base64,"; const char kGeoLocationsPattern[] = "https://www.googleapis.com/geolocation/v1/geolocate?key=*"; diff --git a/common/network_constants.h b/common/network_constants.h index 9a0ee5617a8d..6683fded4421 100644 --- a/common/network_constants.h +++ b/common/network_constants.h @@ -3,6 +3,11 @@ extern const char kBraveUpdatesExtensionsEndpoint[]; +extern const char kBraveReferralsServer[]; +extern const char kBraveReferralsHeadersPath[]; +extern const char kBraveReferralsInitPath[]; +extern const char kBraveReferralsActivityPath[]; + extern const char kEmptyDataURI[]; extern const char kJSDataURLPrefix[]; extern const char kGeoLocationsPattern[]; @@ -22,4 +27,3 @@ extern const char kUserAgentHeader[]; extern const char kBittorrentMimeType[]; extern const char kOctetStreamMimeType[]; #endif // BRAVE_COMMON_NETWORK_CONSTANTS_H_ - diff --git a/common/pref_names.cc b/common/pref_names.cc index a592790ce379..972434af7daa 100644 --- a/common/pref_names.cc +++ b/common/pref_names.cc @@ -20,3 +20,9 @@ const char kUseAlternatePrivateSearchEngine[] = "brave.use_alternate_private_search_engine"; const char kBraveThemeType[] = "brave.theme.type"; const char kLocationBarIsWide[] = "brave.location_bar_is_wide"; +const char kReferralPromoCode[] = "brave.referral.promo_code"; +const char kReferralDownloadID[] = "brave.referral.download_id"; +const char kReferralTimestamp[] = "brave.referral.timestamp"; +const char kReferralAttemptTimestamp[] = "brave.referral.referral_attempt_timestamp"; +const char kReferralAttemptCount[] = "brave.referral.referral_attempt_count"; +const char kReferralHeaders[] = "brave.referral.headers"; diff --git a/common/pref_names.h b/common/pref_names.h index e5fbabd24cf7..0791e6485618 100644 --- a/common/pref_names.h +++ b/common/pref_names.h @@ -20,5 +20,11 @@ extern const char kWidevineOptedIn[]; extern const char kUseAlternatePrivateSearchEngine[]; extern const char kBraveThemeType[]; extern const char kLocationBarIsWide[]; +extern const char kReferralPromoCode[]; +extern const char kReferralDownloadID[]; +extern const char kReferralTimestamp[]; +extern const char kReferralAttemptTimestamp[]; +extern const char kReferralAttemptCount[]; +extern const char kReferralHeaders[]; #endif // BRAVE_COMMON_PREF_NAMES_H_ From 11cb1e61836dbf9bd411d6c94d5544ad8aeb9237 Mon Sep 17 00:00:00 2001 From: Emerick Rogul Date: Sat, 25 Aug 2018 07:44:25 -0400 Subject: [PATCH 02/13] Send referral code with update server ping --- browser/brave_stats_updater.cc | 3 ++- browser/brave_stats_updater_params.cc | 5 +++++ browser/brave_stats_updater_params.h | 2 ++ browser/brave_stats_updater_unittest.cc | 3 ++- 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/browser/brave_stats_updater.cc b/browser/brave_stats_updater.cc index 48551dd5ed06..ea0888b3cd66 100644 --- a/browser/brave_stats_updater.cc +++ b/browser/brave_stats_updater.cc @@ -69,7 +69,8 @@ GURL GetUpdateURL(const brave::BraveStatsUpdaterParams& stats_updater_params) { update_url, "first", stats_updater_params.GetFirstCheckMadeParam()); update_url = net::AppendQueryParameter( update_url, "woi", stats_updater_params.GetWeekOfInstallationParam()); - update_url = net::AppendQueryParameter(update_url, "ref", "none"); + update_url = net::AppendQueryParameter( + update_url, "ref", stats_updater_params.GetReferralCodeParam()); return update_url; } diff --git a/browser/brave_stats_updater_params.cc b/browser/brave_stats_updater_params.cc index 54cda39dfed7..a3ad6c68727f 100644 --- a/browser/brave_stats_updater_params.cc +++ b/browser/brave_stats_updater_params.cc @@ -54,6 +54,10 @@ std::string BraveStatsUpdaterParams::GetWeekOfInstallationParam() const { return week_of_installation_; } +std::string BraveStatsUpdaterParams::GetReferralCodeParam() const { + return referral_promo_code_.empty() ? "none" : referral_promo_code_; +} + void BraveStatsUpdaterParams::LoadPrefs() { last_check_ymd_ = pref_service_->GetString(kLastCheckYMD); last_check_woy_ = pref_service_->GetInteger(kLastCheckWOY); @@ -62,6 +66,7 @@ void BraveStatsUpdaterParams::LoadPrefs() { week_of_installation_ = pref_service_->GetString(kWeekOfInstallation); if (week_of_installation_.empty()) week_of_installation_ = GetLastMondayAsYMD(); + referral_promo_code_ = pref_service_->GetString(kReferralPromoCode); } void BraveStatsUpdaterParams::SavePrefs() { diff --git a/browser/brave_stats_updater_params.h b/browser/brave_stats_updater_params.h index 97e91bd7022c..9e0e8f1afa60 100644 --- a/browser/brave_stats_updater_params.h +++ b/browser/brave_stats_updater_params.h @@ -31,6 +31,7 @@ class BraveStatsUpdaterParams { std::string GetMonthlyParam() const; std::string GetFirstCheckMadeParam() const; std::string GetWeekOfInstallationParam() const; + std::string GetReferralCodeParam() const; void SavePrefs(); @@ -44,6 +45,7 @@ class BraveStatsUpdaterParams { int last_check_month_; bool first_check_made_; std::string week_of_installation_; + std::string referral_promo_code_; void LoadPrefs(); diff --git a/browser/brave_stats_updater_unittest.cc b/browser/brave_stats_updater_unittest.cc index 39c955944644..122cbe776805 100644 --- a/browser/brave_stats_updater_unittest.cc +++ b/browser/brave_stats_updater_unittest.cc @@ -4,8 +4,8 @@ #include "brave/browser/brave_stats_updater.h" -#include "brave/browser/brave_stats_updater.h" #include "brave/browser/brave_stats_updater_params.h" +#include "brave/browser/referrals/brave_referrals_service.h" #include "brave/common/pref_names.h" #include "chrome/browser/browser_process.h" #include "components/prefs/testing_pref_service.h" @@ -32,6 +32,7 @@ class BraveStatsUpdaterTest: public testing::Test { ~BraveStatsUpdaterTest() override {} void SetUp() override { brave::RegisterPrefsForBraveStatsUpdater(testing_local_state_.registry()); + brave::RegisterPrefsForBraveReferralsService(testing_local_state_.registry()); } PrefService* GetLocalState() { return &testing_local_state_; } From 59d53b5f560720fb387d285cd0f6e1703cffa257 Mon Sep 17 00:00:00 2001 From: Emerick Rogul Date: Mon, 10 Sep 2018 14:11:03 -0400 Subject: [PATCH 03/13] On Windows, parse referral code from mini installer's filename After parsing the referral code, we pass it to setup.exe via the --brave-referral-code flag. The setup program will write the referral code out to user-data-dir. --- ...ler-mini_installer-mini_installer.cc.patch | 132 +++++++++++++++++- 1 file changed, 129 insertions(+), 3 deletions(-) diff --git a/patches/chrome-installer-mini_installer-mini_installer.cc.patch b/patches/chrome-installer-mini_installer-mini_installer.cc.patch index 83729b59c308..e0492a8aef8d 100644 --- a/patches/chrome-installer-mini_installer-mini_installer.cc.patch +++ b/patches/chrome-installer-mini_installer-mini_installer.cc.patch @@ -1,5 +1,5 @@ diff --git a/chrome/installer/mini_installer/mini_installer.cc b/chrome/installer/mini_installer/mini_installer.cc -index 1f39abbeb2579098a54fa82612199f0307ea03b4..be08f89c43599fc766048d230572e71ada102169 100644 +index 1f39abbeb2579098a54fa82612199f0307ea03b4..86fe3efd30bad573dba8b73be4788378b9d1f927 100644 --- a/chrome/installer/mini_installer/mini_installer.cc +++ b/chrome/installer/mini_installer/mini_installer.cc @@ -61,7 +61,7 @@ struct Context { @@ -11,7 +11,133 @@ index 1f39abbeb2579098a54fa82612199f0307ea03b4..be08f89c43599fc766048d230572e71a // Opens the Google Update ClientState key. If |binaries| is false, opens the // key for Google Chrome or Chrome SxS (canary). If |binaries| is true and an // existing multi-install Chrome is being updated, opens the key for the -@@ -873,7 +873,7 @@ ProcessExitResult WMain(HMODULE module) { +@@ -142,6 +142,105 @@ void SetInstallerFlags(const Configuration& configuration) { + } + #endif // GOOGLE_CHROME_BUILD + ++#if defined(BRAVE_CHROMIUM_BUILD) ++typedef StackString<128> ReferralCodeString; ++ ++bool ParseStandardReferralCode(const wchar_t* filename, ReferralCodeString& referral_code) { ++ // Scan backwards for last dash in filename. ++ const wchar_t* scan = filename + lstrlen(filename) - 1; ++ while (scan != filename && *scan != L'-') ++ --scan; ++ ++ if (*scan++ != L'-') ++ return false; ++ ++ // Standard referral code is 6 characters. ++ const wchar_t* ref_code = scan; ++ if (lstrlen(ref_code) != 6) ++ return false; ++ ++ // Ensure that first half of referral code is alphabetic. ++ for (int i = 0; i < 3; ++i) { ++ if ((ref_code[i] < L'a' || ref_code[i] > L'z') && ++ (ref_code[i] < L'A' || ref_code[i] > L'Z')) ++ return false; ++ } ++ ++ // Ensure that second half of referral code is numeric. ++ for (int i = 3; i < 6; ++i) { ++ if (ref_code[i] < L'0' || ref_code[i] > L'9') ++ return false; ++ } ++ ++ if (!referral_code.assign(ref_code)) ++ return false; ++ ++ return true; ++} ++ ++bool ParseExtendedReferralCode(const wchar_t* filename, ReferralCodeString& referral_code) { ++ // Scan backwards for second-to-last dash in filename, since this ++ // type of referral code has an embedded dash. ++ const wchar_t* scan = filename + lstrlen(filename) - 1; ++ while (scan != filename && *scan != L'-') ++ --scan; ++ ++ if (*scan-- != L'-') ++ return false; ++ ++ while (scan != filename && *scan != L'-') ++ --scan; ++ ++ if (*scan++ != L'-') ++ return false; ++ ++ // Ensure that referral code is alphabetic. ++ const wchar_t* ref_code = scan; ++ int dashes = 0; ++ for (int i = 0; i < lstrlen(ref_code); ++i) { ++ if ((ref_code[i] < L'a' || ref_code[i] > L'z') && ++ (ref_code[i] < L'A' || ref_code[i] > L'Z') && (ref_code[i] != L'-')) ++ return NULL; ++ if (ref_code[i] == L'-') ++ ++dashes; ++ } ++ ++ // Ensure that referral code contains exactly one dash. ++ if (dashes != 1) ++ return false; ++ ++ if (!referral_code.assign(ref_code)) ++ return false; ++ ++ return true; ++} ++ ++bool ParseReferralCode(const wchar_t* program, ReferralCodeString& referral_code) { ++ PathString filename; ++ if (!filename.assign(GetNameFromPathExt(program, lstrlen(program)))) ++ return false; ++ ++ // Strip extension from filename. ++ const wchar_t* scan = filename.get() + filename.length() - 1; ++ while (scan != filename.get() && *scan != L'.') ++ --scan; ++ ++ if (*scan == L'.') ++ filename.truncate_at(scan - filename.get()); ++ ++ // First check for 6-character standard referral code XXXDDD, where ++ // X is an alphabetic character and D is a numeric character. If not ++ // found, check for an alphabetic referral code of any length in the ++ // form XXX-XXX. ++ if (!ParseStandardReferralCode(filename.get(), referral_code) && ++ !ParseExtendedReferralCode(filename.get(), referral_code)) { ++ return false; ++ } ++ ++ return true; ++} ++#endif // BRAVE_CHROMIUM_BUILD ++ + // Gets the setup.exe path from Registry by looking at the value of Uninstall + // string. |size| is measured in wchar_t units. + ProcessExitResult GetSetupExePathForAppGuid(bool system_level, +@@ -526,6 +625,19 @@ ProcessExitResult RunSetup(const Configuration& configuration, + // on to setup.exe + AppendCommandLineFlags(configuration.command_line(), &cmd_line); + ++#if defined(BRAVE_CHROMIUM_BUILD) ++ ReferralCodeString referral_code; ++ if (ParseReferralCode(configuration.program(), referral_code)) { ++ if (!cmd_line.append(L" --") || ++ !cmd_line.append(L"brave-referral-code") || ++ !cmd_line.append(L"=\"") || ++ !cmd_line.append(referral_code.get()) || ++ !cmd_line.append(L"\"")) { ++ return ProcessExitResult(COMMAND_STRING_OVERFLOW); ++ } ++ } ++#endif ++ + return RunProcessAndWait(setup_exe.get(), cmd_line.get(), + RUN_SETUP_FAILED_FILE_NOT_FOUND, + RUN_SETUP_FAILED_PATH_NOT_FOUND, +@@ -873,7 +985,7 @@ ProcessExitResult WMain(HMODULE module) { if (!GetWorkDir(module, &base_path, &exit_code)) return exit_code; @@ -20,7 +146,7 @@ index 1f39abbeb2579098a54fa82612199f0307ea03b4..be08f89c43599fc766048d230572e71a // Set the magic suffix in registry to try full installer next time. We ignore // any errors here and we try to set the suffix for user level unless // GoogleUpdateIsMachine=1 is present in the environment or --system-level is -@@ -898,7 +898,7 @@ ProcessExitResult WMain(HMODULE module) { +@@ -898,7 +1010,7 @@ ProcessExitResult WMain(HMODULE module) { if (ShouldDeleteExtractedFiles()) DeleteExtractedFiles(base_path.get(), archive_path.get(), setup_path.get()); From b3f33546d18b47369954cbb628afe4677b021e2c Mon Sep 17 00:00:00 2001 From: Emerick Rogul Date: Mon, 10 Sep 2018 14:15:19 -0400 Subject: [PATCH 04/13] On Windows, write referral code out to user-data-dir The mini installer passes the referral code to setup via the --brave-referral-code command line option --- .../chrome/installer/setup/setup_main.cc | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 chromium_src/chrome/installer/setup/setup_main.cc diff --git a/chromium_src/chrome/installer/setup/setup_main.cc b/chromium_src/chrome/installer/setup/setup_main.cc new file mode 100644 index 000000000000..2ad0ec3c6068 --- /dev/null +++ b/chromium_src/chrome/installer/setup/setup_main.cc @@ -0,0 +1,35 @@ +/* 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/. */ + +#define wWinMain wWinMain_ChromiumImpl +#include "../../../../../chrome/installer/setup/setup_main.cc" +#undef wWinMain + +const char kBraveReferralCode[] = "brave-referral-code"; + +int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prev_instance, + wchar_t* command_line, int show_command) { + int return_code = wWinMain_ChromiumImpl(instance, prev_instance, command_line, + show_command); + if (!return_code) { + const base::CommandLine& cmd_line = *base::CommandLine::ForCurrentProcess(); + if (cmd_line.HasSwitch(kBraveReferralCode)) { + const std::string referral_code = + cmd_line.GetSwitchValueASCII(kBraveReferralCode); + if (!referral_code.empty()) { + base::FilePath user_data_dir; + base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); + base::FilePath referral_code_path = + user_data_dir.AppendASCII("promoCode"); + if (!base::WriteFile(referral_code_path, referral_code.c_str(), + referral_code.size())) { + LOG(ERROR) << "Failed to write referral code " << referral_code + << " to " << referral_code_path; + } + } + } + } + + return return_code; +} From 021a3e6e47f64784d2f6e84a899ff0fee08c532d Mon Sep 17 00:00:00 2001 From: Emerick Rogul Date: Fri, 14 Sep 2018 15:11:21 -0400 Subject: [PATCH 05/13] On Mac, create an install pkg to parse referral code When run against the release channel, this creates a signed install pkg that parses a referral code (if any) from its filename and writes it to user-data-dir. When run against any other channel, no pkg is created. --- BUILD.gn | 6 ++++ build/config.gni | 1 + build/mac/BUILD.gn | 40 ++++++++++++++++++++++++ build/mac/create_pkg.sh | 51 ++++++++++++++++++++++++++++++ build/mac/pkg-scripts/postinstall | 52 +++++++++++++++++++++++++++++++ build/mac/sign_pkg.sh | 32 +++++++++++++++++++ 6 files changed, 182 insertions(+) create mode 100755 build/mac/create_pkg.sh create mode 100755 build/mac/pkg-scripts/postinstall create mode 100755 build/mac/sign_pkg.sh diff --git a/BUILD.gn b/BUILD.gn index cf288404ee23..bb21cab466d5 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -88,6 +88,12 @@ group("create_dist") { } if (is_mac) { deps += [ "build/mac:create_dist_mac" ] + if (brave_channel == "") { + deps += [ + "build/mac:create_pkg", + "build/mac:sign_pkg", + ] + } } if (is_linux) { deps += [ diff --git a/build/config.gni b/build/config.gni index 866d00c11f54..966268167751 100644 --- a/build/config.gni +++ b/build/config.gni @@ -44,6 +44,7 @@ if (is_win) { } else if (is_mac) { brave_exe = "$chrome_product_full_name.app" brave_dmg = "$chrome_product_full_name.dmg" + brave_pkg = "$chrome_product_full_name.pkg" brave_product_dir_name_suffix = "" if (is_official_build) { diff --git a/build/mac/BUILD.gn b/build/mac/BUILD.gn index 1750ca5f7848..a5df63af683d 100644 --- a/build/mac/BUILD.gn +++ b/build/mac/BUILD.gn @@ -44,6 +44,46 @@ action("sign_app") { ] } +action("create_pkg") { + output = "$root_out_dir/unsigned/$brave_pkg" + script = "//build/gn_run_binary.py" + shell_script = "//brave/build/mac/create_pkg.sh" + inputs = [ + script, + shell_script, + ] + outputs = [ output ] + args = [ + rebase_path(shell_script, root_build_dir), + rebase_path(_target_app_path, root_build_dir), + rebase_path("//brave/build/mac/pkg-scripts"), + rebase_path("$root_out_dir/Brave Browser Component.plist"), + "unsigned/$brave_pkg", + ] + + deps = [":sign_app"] +} + +action("sign_pkg") { + script = "//build/gn_run_binary.py" + shell_script = "sign_pkg.sh" + inputs = [ + script, + shell_script, + "$root_out_dir/unsigned/$brave_pkg", + ] + outputs = [ "${root_out_dir}/signing/$brave_pkg" ] + args = [ + rebase_path(shell_script, root_build_dir), + rebase_path("$root_out_dir/unsigned/$brave_pkg"), + rebase_path("$root_out_dir/$brave_pkg"), + keychain_db, + mac_signing_identifier, + ] + + deps = [":create_pkg"] +} + action("create_dmg") { output = "$root_out_dir/unsigned/$brave_dmg" script = "//build/gn_run_binary.py" diff --git a/build/mac/create_pkg.sh b/build/mac/create_pkg.sh new file mode 100755 index 000000000000..ed4858a3dad7 --- /dev/null +++ b/build/mac/create_pkg.sh @@ -0,0 +1,51 @@ +#!/usr/bin/env bash + +if [[ $# -lt "4" ]]; then + echo "usage: $0 " + exit 1 +fi + +APP="${1}" +PKG_SCRIPTS="${2}" +COMPONENT_PLIST="${3}" +PKG_OUT="${4}" + +PKG_ROOT=pkg_root + +function check_exit() { + return=$?; + if [[ $return -eq 0 ]]; then + echo "[INFO] $0 succeeded" + else + echo "[ERROR] $0 failed" + fi + + exit $return +} + +trap check_exit EXIT + +# Delete old pkg root directory, if any +if [[ -d "$PKG_ROOT" ]]; then + rm -rf "$PKG_ROOT" +fi + +# Create the pkg root directory +mkdir "$PKG_ROOT" + +# Copy the application into the pkg root directory +cp -a "$APP" "$PKG_ROOT" + +# Create a template component property list +pkgbuild --analyze --root "$PKG_ROOT" "$COMPONENT_PLIST" + +# Mark the bundle as non-relocatable +plutil -replace BundleIsRelocatable -bool NO "$COMPONENT_PLIST" + +# Create the pkg +pkgbuild --identifier com.brave.Brave \ + --install-location /Applications \ + --root "$PKG_ROOT" \ + --scripts "$PKG_SCRIPTS" \ + --component-plist "$COMPONENT_PLIST" \ + "$PKG_OUT" diff --git a/build/mac/pkg-scripts/postinstall b/build/mac/pkg-scripts/postinstall new file mode 100755 index 000000000000..a1d3fdf67efb --- /dev/null +++ b/build/mac/pkg-scripts/postinstall @@ -0,0 +1,52 @@ +#!/bin/sh +# This postinstall script is run on macOS pkg installers + +# Extract a referral / promo code from the installer path of the format /dir/path/Setup-Brave-Anything-xxx001.pkg +# where the promo code would be xxx001 +installerPath=$1 +installationPath=$2 + +# TODO: ugly to assume the name of the app, especially with multi-channel. +# Luckily for now, release channel is the only channel with a pkg installer. +installationAppPath="$installationPath/Brave Browser.app" +installerPathPromoCodeRegex='.+-(([a-zA-Z0-9]{3}[0-9]{3})|([a-zA-Z]{1,}-[a-zA-Z]{1,}))([[:blank:]]?\([0-9]+\))?\.pkg$' +userDataDir="$HOME/Library/Application Support/BraveSoftware/Brave-Browser" +promoCodePath="$userDataDir/promoCode" + +# pkg runs this script as root so we need to get current username +userName="$USER" + +echo "Installer path is: $installerPath" +echo "Username is: $userName" +echo "Installation app path is: $installationAppPath" + +# Fix the permissions on installed .app so that updater has permissions to write new contents. +# By default pkg will install the .app with root:wheel owner and 'drwxr-xr-x' permission. +# We'll allow all admin users of the machine permissions to update the app, as well as the installing-user +# (who may not be an admin). +sudo chmod -R 775 "$installationAppPath" +sudo chown -R $userName "$installationAppPath" +sudo chgrp -R admin "$installationAppPath" + +# Detect if installer contained a referral promotion code within the filename +if [[ $installerPath =~ $installerPathPromoCodeRegex ]]; then + echo "Installer path matched for promo code" + n=${#BASH_REMATCH[*]} + if [ $n -ge 1 ]; then + promoCode=${BASH_REMATCH[1]} + echo "Got promo code: $promoCode" + echo "Writing to user data directory at: $userDataDir/promoCode" + # TODO: it is a bit ugly to assume the user-data path here, and to manually + # write to it and hopefully set the correct permissions. An alternative would + # be to run Brave with a flag, similar to the process for Windows. + mkdir -p "$userDataDir" + echo "$promoCode" > "$promoCodePath" + # fix permissions + sudo chown "$userName" "$userDataDir" + sudo chown "$userName" "$promoCodePath" + fi +else + echo "Installer path did not match for promo code" +fi + +exit 0 diff --git a/build/mac/sign_pkg.sh b/build/mac/sign_pkg.sh new file mode 100755 index 000000000000..b627d3d0a76e --- /dev/null +++ b/build/mac/sign_pkg.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash + +set -euo pipefail + +if [[ $# -lt "4" ]]; then + echo "usage: $0 " + exit 1 +fi + +SOURCE="${1}" +DEST="${2}" +MAC_SIGNING_KEYCHAIN="${3}" +MAC_SIGNING_IDENTIFIER="${4}" + +function check_exit() { + return=$?; + if [[ $return -eq 0 ]]; then + echo "[INFO] $0 succeeded" + else + echo "[ERROR] $0 failed" + fi + + exit $return +} + +trap check_exit EXIT + +if [[ -f $DEST ]]; then + rm -f "$DEST" +fi + +/usr/bin/productsign --sign "$MAC_SIGNING_IDENTIFIER" --keychain "$MAC_SIGNING_KEYCHAIN" "$SOURCE" "$DEST" From df9f6fcb3b0278802a94448d7ed12ad038961fb5 Mon Sep 17 00:00:00 2001 From: Emerick Rogul Date: Mon, 17 Sep 2018 14:59:11 -0400 Subject: [PATCH 06/13] Set custom referral headers when domain matches --- browser/net/BUILD.gn | 6 +- browser/net/brave_network_delegate_base.cc | 18 +++++- browser/net/brave_network_delegate_base.h | 2 + browser/net/brave_profile_network_delegate.cc | 14 +++-- ...brave_referrals_network_delegate_helper.cc | 56 +++++++++++++++++++ .../brave_referrals_network_delegate_helper.h | 27 +++++++++ browser/net/url_context.h | 1 + 7 files changed, 115 insertions(+), 9 deletions(-) create mode 100644 browser/net/brave_referrals_network_delegate_helper.cc create mode 100644 browser/net/brave_referrals_network_delegate_helper.h diff --git a/browser/net/BUILD.gn b/browser/net/BUILD.gn index 507e213f7d90..e613ef8a48a2 100644 --- a/browser/net/BUILD.gn +++ b/browser/net/BUILD.gn @@ -5,12 +5,14 @@ source_set("net") { sources = [ "brave_common_static_redirect_network_delegate_helper.cc", "brave_common_static_redirect_network_delegate_helper.h", - "brave_network_delegate_base.cc", - "brave_network_delegate_base.h", "brave_httpse_network_delegate_helper.cc", "brave_httpse_network_delegate_helper.h", + "brave_network_delegate_base.cc", + "brave_network_delegate_base.h", "brave_profile_network_delegate.cc", "brave_profile_network_delegate.h", + "brave_referrals_network_delegate_helper.cc", + "brave_referrals_network_delegate_helper.h", "brave_site_hacks_network_delegate_helper.cc", "brave_site_hacks_network_delegate_helper.h", "brave_static_redirect_network_delegate_helper.cc", diff --git a/browser/net/brave_network_delegate_base.cc b/browser/net/brave_network_delegate_base.cc index 99093ad0b39d..16a64651302f 100644 --- a/browser/net/brave_network_delegate_base.cc +++ b/browser/net/brave_network_delegate_base.cc @@ -7,6 +7,9 @@ #include #include "brave/browser/net/url_context.h" +#include "brave/common/pref_names.h" +#include "chrome/browser/browser_process.h" +#include "components/prefs/pref_service.h" #include "content/public/browser/browser_thread.h" #include "net/url_request/url_request.h" @@ -14,13 +17,23 @@ using content::BrowserThread; BraveNetworkDelegateBase::BraveNetworkDelegateBase( - extensions::EventRouterForwarder* event_router) : - ChromeNetworkDelegate(event_router) { + extensions::EventRouterForwarder* event_router) + : ChromeNetworkDelegate(event_router), referral_headers_list_(nullptr) { + // Retrieve the current referral headers, if any. + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + base::Bind(&BraveNetworkDelegateBase::GetReferralHeaders, + base::Unretained(this))); } BraveNetworkDelegateBase::~BraveNetworkDelegateBase() { } +void BraveNetworkDelegateBase::GetReferralHeaders() { + referral_headers_list_ = + g_browser_process->local_state()->GetList(kReferralHeaders); +} + int BraveNetworkDelegateBase::OnBeforeURLRequest(net::URLRequest* request, net::CompletionOnceCallback callback, GURL* new_url) { @@ -49,6 +62,7 @@ int BraveNetworkDelegateBase::OnBeforeStartTransaction(net::URLRequest* request, ctx->headers = headers; ctx->request_identifier = request->identifier(); ctx->event_type = brave::kOnBeforeStartTransaction; + ctx->referral_headers_list = referral_headers_list_; RunNextCallback(request, nullptr, ctx); return net::ERR_IO_PENDING; } diff --git a/browser/net/brave_network_delegate_base.h b/browser/net/brave_network_delegate_base.h index a7dd170136fd..fd45d8f4e512 100644 --- a/browser/net/brave_network_delegate_base.h +++ b/browser/net/brave_network_delegate_base.h @@ -59,6 +59,8 @@ class BraveNetworkDelegateBase : public ChromeNetworkDelegate { headers_received_callbacks_; private: + void GetReferralHeaders(); + const base::ListValue* referral_headers_list_; std::map callbacks_; DISALLOW_COPY_AND_ASSIGN(BraveNetworkDelegateBase); diff --git a/browser/net/brave_profile_network_delegate.cc b/browser/net/brave_profile_network_delegate.cc index 18a6473e84b7..573991e395ea 100644 --- a/browser/net/brave_profile_network_delegate.cc +++ b/browser/net/brave_profile_network_delegate.cc @@ -6,14 +6,14 @@ #include "brave/browser/net/brave_common_static_redirect_network_delegate_helper.h" #include "brave/browser/net/brave_httpse_network_delegate_helper.h" +#include "brave/browser/net/brave_referrals_network_delegate_helper.h" #include "brave/browser/net/brave_site_hacks_network_delegate_helper.h" +#include "brave/browser/net/brave_tor_network_delegate_helper.h" #include "brave/components/brave_rewards/browser/buildflags/buildflags.h" -#include "brave/components/brave_webtorrent/browser/net/brave_torrent_redirect_network_delegate_helper.h" - #if BUILDFLAG(BRAVE_REWARDS_ENABLED) #include "brave/components/brave_rewards/browser/net/network_delegate_helper.h" #endif -#include "brave/browser/net/brave_tor_network_delegate_helper.h" +#include "brave/components/brave_webtorrent/browser/net/brave_torrent_redirect_network_delegate_helper.h" BraveProfileNetworkDelegate::BraveProfileNetworkDelegate( extensions::EventRouterForwarder* event_router) : @@ -39,9 +39,13 @@ BraveProfileNetworkDelegate::BraveProfileNetworkDelegate( callback = base::Bind(brave::OnBeforeURLRequest_TorWork); before_url_request_callbacks_.push_back(callback); - brave::OnBeforeStartTransactionCallback start_transactions_callback = + brave::OnBeforeStartTransactionCallback start_transaction_callback = base::Bind(brave::OnBeforeStartTransaction_SiteHacksWork); - before_start_transaction_callbacks_.push_back(start_transactions_callback); + before_start_transaction_callbacks_.push_back(start_transaction_callback); + + start_transaction_callback = + base::Bind(brave::OnBeforeStartTransaction_ReferralsWork); + before_start_transaction_callbacks_.push_back(start_transaction_callback); brave::OnHeadersReceivedCallback headers_received_callback = base::Bind( diff --git a/browser/net/brave_referrals_network_delegate_helper.cc b/browser/net/brave_referrals_network_delegate_helper.cc new file mode 100644 index 000000000000..861a1dfbbc52 --- /dev/null +++ b/browser/net/brave_referrals_network_delegate_helper.cc @@ -0,0 +1,56 @@ +/* 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_referrals_network_delegate_helper.h" + +#include "base/values.h" +#include "chrome/browser/browser_process.h" +#include "content/public/browser/browser_thread.h" +#include "extensions/common/url_pattern.h" +#include "net/url_request/url_request.h" + +namespace brave { + +int OnBeforeStartTransaction_ReferralsWork( + net::URLRequest* request, + net::HttpRequestHeaders* headers, + const ResponseCallback& next_callback, + std::shared_ptr ctx) { + if (!ctx->referral_headers_list) + return net::OK; + // If the domain for this request matches one of our target domains, + // set the associated custom headers. + for (const auto& headers_value : *ctx->referral_headers_list) { + const base::Value* domains_list = + headers_value.FindKeyOfType("domains", base::Value::Type::LIST); + if (!domains_list) { + LOG(WARNING) << "Failed to retrieve 'domains' key from referral headers"; + continue; + } + const base::Value* headers_dict = + headers_value.FindKeyOfType("headers", base::Value::Type::DICTIONARY); + if (!headers_dict) { + LOG(WARNING) << "Failed to retrieve 'headers' key from referral headers"; + continue; + } + for (const auto& domain_value : domains_list->GetList()) { + URLPattern url_pattern(URLPattern::SCHEME_HTTPS | + URLPattern::SCHEME_HTTP); + url_pattern.SetScheme("*"); + url_pattern.SetHost(domain_value.GetString()); + url_pattern.SetPath("/*"); + url_pattern.SetMatchSubdomains(true); + if (!url_pattern.MatchesURL(request->url())) + continue; + for (const auto& it : headers_dict->DictItems()) { + headers->SetHeader(it.first, it.second.GetString()); + } + return net::OK; + } + } + + return net::OK; +} + +} // namespace brave diff --git a/browser/net/brave_referrals_network_delegate_helper.h b/browser/net/brave_referrals_network_delegate_helper.h new file mode 100644 index 000000000000..b0df981ce09b --- /dev/null +++ b/browser/net/brave_referrals_network_delegate_helper.h @@ -0,0 +1,27 @@ +/* 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_REFERRALS_NETWORK_DELEGATE_H_ +#define BRAVE_BROWSER_NET_BRAVE_REFERRALS_NETWORK_DELEGATE_H_ + +#include "brave/browser/net/url_context.h" + +struct BraveRequestInfo; + +namespace net { +class HttpRequestHeaders; +class URLRequest; +} + +namespace brave { + +int OnBeforeStartTransaction_ReferralsWork( + net::URLRequest* request, + net::HttpRequestHeaders* headers, + const ResponseCallback& next_callback, + std::shared_ptr ctx); + +} // namespace brave + +#endif // BRAVE_BROWSER_NET_BRAVE_REFERRALS_NETWORK_DELEGATE_H_ diff --git a/browser/net/url_context.h b/browser/net/url_context.h index 0ab116b4537c..873fee9ea372 100644 --- a/browser/net/url_context.h +++ b/browser/net/url_context.h @@ -32,6 +32,7 @@ struct BraveRequestInfo { scoped_refptr* override_response_headers = nullptr; GURL* allowed_unsafe_redirect_url = nullptr; BraveNetworkDelegateEventType event_type = kUnknownEventType; + const base::ListValue* referral_headers_list = nullptr; DISALLOW_COPY_AND_ASSIGN(BraveRequestInfo); }; From 2478e822e4c780df74e3ee529d5645a77ad83481 Mon Sep 17 00:00:00 2001 From: Emerick Rogul Date: Wed, 19 Sep 2018 15:51:46 -0400 Subject: [PATCH 07/13] Delete promo code preference after 90 days --- browser/referrals/brave_referrals_service.cc | 12 ++++++++++++ browser/referrals/brave_referrals_service.h | 1 + 2 files changed, 13 insertions(+) diff --git a/browser/referrals/brave_referrals_service.cc b/browser/referrals/brave_referrals_service.cc index 2989185b9e45..ddac1a6150ad 100644 --- a/browser/referrals/brave_referrals_service.cc +++ b/browser/referrals/brave_referrals_service.cc @@ -90,6 +90,8 @@ void BraveReferralsService::Start() { this, &BraveReferralsService::OnFetchReferralHeadersTimerFired); DCHECK(fetch_referral_headers_timer_->IsRunning()); + // On first run, read the promo code from user-data-dir and + // initialize the referral. std::string download_id = pref_service_->GetString(kReferralDownloadID); if (download_id.empty() && first_run::IsChromeFirstRun()) task_runner_->PostTaskAndReply( @@ -101,6 +103,9 @@ void BraveReferralsService::Start() { else FetchReferralHeaders(); + // Delete the promo code preference, if appropriate. + MaybeDeletePromoCodePref(); + // Check for referral finalization, if appropriate. MaybeCheckForReferralFinalization(); @@ -306,6 +311,13 @@ void BraveReferralsService::MaybeCheckForReferralFinalization() { CheckForReferralFinalization(); } +void BraveReferralsService::MaybeDeletePromoCodePref() const { + base::Time now = base::Time::Now(); + base::Time firstrun_timestamp = first_run::GetFirstRunSentinelCreationTime(); + if (now - firstrun_timestamp >= base::TimeDelta::FromDays(90)) + pref_service_->ClearPref(kReferralPromoCode); +} + std::string BraveReferralsService::BuildReferralInitPayload() const { std::unique_ptr env(base::Environment::Create()); std::string api_key; diff --git a/browser/referrals/brave_referrals_service.h b/browser/referrals/brave_referrals_service.h index 01f23187a9b2..ea7cc2646039 100644 --- a/browser/referrals/brave_referrals_service.h +++ b/browser/referrals/brave_referrals_service.h @@ -36,6 +36,7 @@ class BraveReferralsService { bool ReadPromoCode(); void DeletePromoCodeFile() const; void MaybeCheckForReferralFinalization(); + void MaybeDeletePromoCodePref() const; void InitReferral(); std::string BuildReferralInitPayload() const; std::string BuildReferralFinalizationCheckPayload() const; From 3aebb6bfbd3356ed06b03c8cb96b267304fa312b Mon Sep 17 00:00:00 2001 From: Emerick Rogul Date: Wed, 19 Sep 2018 16:01:46 -0400 Subject: [PATCH 08/13] Pass BRAVE_REFERRALS_API_KEY from config when building and use it --- browser/referrals/BUILD.gn | 6 ++++++ browser/referrals/brave_referrals_service.cc | 16 ++++++++++++---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/browser/referrals/BUILD.gn b/browser/referrals/BUILD.gn index 18f7d015bca3..344359ea4bd3 100644 --- a/browser/referrals/BUILD.gn +++ b/browser/referrals/BUILD.gn @@ -1,9 +1,15 @@ +declare_args() { + brave_referrals_api_key = "" +} + source_set("referrals") { sources = [ "brave_referrals_service.cc", "brave_referrals_service.h", ] + defines = [ "BRAVE_REFERRALS_API_KEY=\"$brave_referrals_api_key\"" ] + deps = [ "//base", "//chrome/common", diff --git a/browser/referrals/brave_referrals_service.cc b/browser/referrals/brave_referrals_service.cc index ddac1a6150ad..6217c62b6736 100644 --- a/browser/referrals/brave_referrals_service.cc +++ b/browser/referrals/brave_referrals_service.cc @@ -319,28 +319,36 @@ void BraveReferralsService::MaybeDeletePromoCodePref() const { } std::string BraveReferralsService::BuildReferralInitPayload() const { + std::string api_key = BRAVE_REFERRALS_API_KEY; std::unique_ptr env(base::Environment::Create()); - std::string api_key; - env->GetVar("REFERRAL_API_KEY", &api_key); + if (env->HasVar("BRAVE_REFERRALS_API_KEY")) + env->GetVar("BRAVE_REFERRALS_API_KEY", &api_key); + base::Value root(base::Value::Type::DICTIONARY); root.SetKey("api_key", base::Value(api_key)); root.SetKey("referral_code", base::Value(promo_code_)); root.SetKey("platform", base::Value(GetPlatformIdentifier())); + std::string result; base::JSONWriter::Write(root, &result); + return result; } std::string BraveReferralsService::BuildReferralFinalizationCheckPayload() const { + std::string api_key = BRAVE_REFERRALS_API_KEY; std::unique_ptr env(base::Environment::Create()); - std::string api_key; - env->GetVar("REFERRAL_API_KEY", &api_key); + if (env->HasVar("BRAVE_REFERRALS_API_KEY")) + env->GetVar("BRAVE_REFERRALS_API_KEY", &api_key); + base::Value root(base::Value::Type::DICTIONARY); root.SetKey("api_key", base::Value(api_key)); root.SetKey("download_id", base::Value(pref_service_->GetString(kReferralDownloadID))); + std::string result; base::JSONWriter::Write(root, &result); + return result; } From 8fc5ea80cdd5a88c88180598f7d95ac0303072b0 Mon Sep 17 00:00:00 2001 From: Emerick Rogul Date: Thu, 20 Sep 2018 17:03:52 -0400 Subject: [PATCH 09/13] Add unit tests for referrals network delegate --- ...errals_network_delegate_helper_unittest.cc | 122 ++++++++++++++++++ test/BUILD.gn | 1 + 2 files changed, 123 insertions(+) create mode 100644 browser/net/brave_referrals_network_delegate_helper_unittest.cc diff --git a/browser/net/brave_referrals_network_delegate_helper_unittest.cc b/browser/net/brave_referrals_network_delegate_helper_unittest.cc new file mode 100644 index 000000000000..66e4c8f657b1 --- /dev/null +++ b/browser/net/brave_referrals_network_delegate_helper_unittest.cc @@ -0,0 +1,122 @@ +/* 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_referrals_network_delegate_helper.h" + +#include "base/json/json_reader.h" +#include "brave/browser/net/url_context.h" +#include "brave/common/network_constants.h" +#include "chrome/test/base/chrome_render_view_host_test_harness.h" +#include "net/traffic_annotation/network_traffic_annotation_test_helper.h" +#include "net/url_request/url_request_test_util.h" +#include "url/gurl.h" +#include "url/url_constants.h" + +const char kTestReferralHeaders[] = R"( + [ + { + "domains": [ + "marketwatch.com", + "barrons.com" + ], + "headers": { + "X-Brave-Partner":"dowjones" + }, + "cookieNames": [ + ], + "expiration":31536000000 + }, + { + "domains": [ + "townsquareblogs.com", + "tasteofcountry.com", + "ultimateclassicrock.com", + "xxlmag.com", + "popcrush.com" + ], + "headers": { + "X-Brave-Partner":"townsquare" + }, + "cookieNames":[ + ], + "expiration":31536000000 + } + ])"; + +namespace { + +class BraveReferralsNetworkDelegateHelperTest : public testing::Test { + public: + BraveReferralsNetworkDelegateHelperTest() + : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP), + context_(new net::TestURLRequestContext(true)) { + } + ~BraveReferralsNetworkDelegateHelperTest() override {} + void SetUp() override { + context_->Init(); + } + net::TestURLRequestContext* context() { return context_.get(); } + + private: + content::TestBrowserThreadBundle thread_bundle_; + std::unique_ptr context_; +}; + +TEST_F(BraveReferralsNetworkDelegateHelperTest, ReplaceHeadersForMatchingDomain) { + GURL url("https://www.marketwatch.com"); + net::TestDelegate test_delegate; + std::unique_ptr request = context()->CreateRequest( + url, net::IDLE, &test_delegate, TRAFFIC_ANNOTATION_FOR_TESTS); + + std::unique_ptr referral_headers = + base::JSONReader().ReadToValue(kTestReferralHeaders); + ASSERT_TRUE(referral_headers); + ASSERT_TRUE(referral_headers->is_list()); + + base::ListValue referral_headers_list = + base::ListValue(referral_headers->GetList()); + + net::HttpRequestHeaders headers; + brave::ResponseCallback callback; + std::shared_ptr brave_request_info( + new brave::BraveRequestInfo()); + brave_request_info->referral_headers_list = &referral_headers_list; + int ret = brave::OnBeforeStartTransaction_ReferralsWork( + request.get(), &headers, callback, brave_request_info); + + std::string partner_header; + headers.GetHeader("X-Brave-Partner", &partner_header); + EXPECT_EQ(partner_header, "dowjones"); + + EXPECT_EQ(ret, net::OK); +} + +TEST_F(BraveReferralsNetworkDelegateHelperTest, NoReplaceHeadersForNonMatchingDomain) { + GURL url("https://www.google.com"); + net::TestDelegate test_delegate; + std::unique_ptr request = context()->CreateRequest( + url, net::IDLE, &test_delegate, TRAFFIC_ANNOTATION_FOR_TESTS); + + std::unique_ptr referral_headers = + base::JSONReader().ReadToValue(kTestReferralHeaders); + ASSERT_TRUE(referral_headers); + ASSERT_TRUE(referral_headers->is_list()); + + base::ListValue referral_headers_list = + base::ListValue(referral_headers->GetList()); + + net::HttpRequestHeaders headers; + brave::ResponseCallback callback; + std::shared_ptr brave_request_info( + new brave::BraveRequestInfo()); + brave_request_info->referral_headers_list = &referral_headers_list; + int ret = brave::OnBeforeStartTransaction_ReferralsWork( + request.get(), &headers, callback, brave_request_info); + + EXPECT_FALSE(headers.HasHeader("X-Brave-Partner")); + + EXPECT_EQ(ret, net::OK); +} + +} // namespace diff --git a/test/BUILD.gn b/test/BUILD.gn index 29a50473ebe0..990d143fa4ac 100644 --- a/test/BUILD.gn +++ b/test/BUILD.gn @@ -32,6 +32,7 @@ test("brave_unit_tests") { "//brave/browser/brave_resources_util_unittest.cc", "//brave/browser/brave_stats_updater_unittest.cc", "//brave/browser/net/brave_common_static_redirect_network_delegate_helper_unittest.cc", + "//brave/browser/net/brave_referrals_network_delegate_helper_unittest.cc", "//brave/browser/net/brave_site_hacks_network_delegate_helper_unittest.cc", "//brave/browser/net/brave_static_redirect_network_delegate_helper_unittest.cc", "//brave/browser/net/brave_tor_network_delegate_helper_unittest.cc", From 7c881d9ae60a37871e6cbbb2192014160cab8978 Mon Sep 17 00:00:00 2001 From: Emerick Rogul Date: Mon, 24 Sep 2018 13:19:41 -0400 Subject: [PATCH 10/13] Don't retrieve first run time on main thread Retrieving the time is a blocking operation and will trigger an assertion on the main thread. Instead, post a task to retrieve the first run time and when it completes post tasks back to the main thread to perform associated bookkeeping (these need to run on the main thread as they interact with the preference service). --- browser/referrals/brave_referrals_service.cc | 40 +++++++++++++++----- browser/referrals/brave_referrals_service.h | 2 + 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/browser/referrals/brave_referrals_service.cc b/browser/referrals/brave_referrals_service.cc index 6217c62b6736..9900c9be7f3e 100644 --- a/browser/referrals/brave_referrals_service.cc +++ b/browser/referrals/brave_referrals_service.cc @@ -25,6 +25,8 @@ #include "chrome/common/chrome_paths.h" #include "components/prefs/pref_registry_simple.h" #include "components/prefs/pref_service.h" +#include "content/public/browser/browser_task_traits.h" +#include "content/public/browser/browser_thread.h" #include "net/base/load_flags.h" #include "net/traffic_annotation/network_traffic_annotation.h" #include "services/network/public/cpp/resource_request.h" @@ -82,6 +84,11 @@ void BraveReferralsService::Start() { if (initialized_) return; + // Retrieve first run sentinel creation time. + task_runner_->PostTask(FROM_HERE, + base::Bind(&BraveReferralsService::GetFirstRunTime, + base::Unretained(this))); + // Periodically fetch referral headers. DCHECK(!fetch_referral_headers_timer_); fetch_referral_headers_timer_ = std::make_unique(); @@ -103,12 +110,6 @@ void BraveReferralsService::Start() { else FetchReferralHeaders(); - // Delete the promo code preference, if appropriate. - MaybeDeletePromoCodePref(); - - // Check for referral finalization, if appropriate. - MaybeCheckForReferralFinalization(); - initialized_ = true; } @@ -244,6 +245,24 @@ void BraveReferralsService::PerformFirstRunTasks() { ReadPromoCode(); } +void BraveReferralsService::GetFirstRunTime() { + first_run_timestamp_ = first_run::GetFirstRunSentinelCreationTime(); + if (first_run_timestamp_.is_null()) + return; + + // Delete the promo code preference, if appropriate. + base::PostTaskWithTraits( + FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(&BraveReferralsService::MaybeDeletePromoCodePref, + base::Unretained(this))); + + // Check for referral finalization, if appropriate. + base::PostTaskWithTraits( + FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(&BraveReferralsService::MaybeCheckForReferralFinalization, + base::Unretained(this))); +} + base::FilePath BraveReferralsService::GetPromoCodeFileName() const { base::FilePath user_data_dir; base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); @@ -279,6 +298,8 @@ void BraveReferralsService::DeletePromoCodeFile() const { } void BraveReferralsService::MaybeCheckForReferralFinalization() { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + std::string download_id = pref_service_->GetString(kReferralDownloadID); if (download_id.empty()) { return; @@ -287,8 +308,7 @@ void BraveReferralsService::MaybeCheckForReferralFinalization() { // Only check for referral finalization after 30 days have elapsed // since first run. base::Time now = base::Time::Now(); - base::Time firstrun_timestamp = first_run::GetFirstRunSentinelCreationTime(); - if (now - firstrun_timestamp < base::TimeDelta::FromDays(30)) + if (now - first_run_timestamp_ < base::TimeDelta::FromDays(30)) return; // Only check for referral finalization 30 times, with a 24-hour @@ -312,9 +332,9 @@ void BraveReferralsService::MaybeCheckForReferralFinalization() { } void BraveReferralsService::MaybeDeletePromoCodePref() const { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); base::Time now = base::Time::Now(); - base::Time firstrun_timestamp = first_run::GetFirstRunSentinelCreationTime(); - if (now - firstrun_timestamp >= base::TimeDelta::FromDays(90)) + if (now - first_run_timestamp_ >= base::TimeDelta::FromDays(90)) pref_service_->ClearPref(kReferralPromoCode); } diff --git a/browser/referrals/brave_referrals_service.h b/browser/referrals/brave_referrals_service.h index ea7cc2646039..ef2acca54d40 100644 --- a/browser/referrals/brave_referrals_service.h +++ b/browser/referrals/brave_referrals_service.h @@ -32,6 +32,7 @@ class BraveReferralsService { private: void PerformFirstRunTasks(); + void GetFirstRunTime(); base::FilePath GetPromoCodeFileName() const; bool ReadPromoCode(); void DeletePromoCodeFile() const; @@ -64,6 +65,7 @@ class BraveReferralsService { void OnFirstRunTasksComplete(); bool initialized_; + base::Time first_run_timestamp_; scoped_refptr task_runner_; std::unique_ptr referral_headers_loader_; std::unique_ptr referral_init_loader_; From 4bd8ebad7da80d104c83faecdebc506fb1b7cfb5 Mon Sep 17 00:00:00 2001 From: Emerick Rogul Date: Mon, 24 Sep 2018 13:22:20 -0400 Subject: [PATCH 11/13] Validate response_body before attempting to log its contents --- browser/referrals/brave_referrals_service.cc | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/browser/referrals/brave_referrals_service.cc b/browser/referrals/brave_referrals_service.cc index 9900c9be7f3e..8603bc490a38 100644 --- a/browser/referrals/brave_referrals_service.cc +++ b/browser/referrals/brave_referrals_service.cc @@ -131,10 +131,12 @@ void BraveReferralsService::OnReferralHeadersLoadComplete( referral_headers_loader_->ResponseInfo()->headers->response_code(); if (referral_headers_loader_->NetError() != net::OK || response_code < 200 || response_code > 299) { + const std::string safe_response_body = + response_body ? *response_body : std::string(); LOG(ERROR) << "Failed to fetch headers from referral server" << ", error: " << referral_headers_loader_->NetError() << ", response code: " << response_code - << ", payload: " << *response_body + << ", payload: " << safe_response_body << ", url: " << referral_headers_loader_->GetFinalURL().spec(); return; } @@ -156,10 +158,12 @@ void BraveReferralsService::OnReferralInitLoadComplete( referral_init_loader_->ResponseInfo()->headers->response_code(); if (referral_init_loader_->NetError() != net::OK || response_code < 200 || response_code > 299) { + const std::string safe_response_body = + response_body ? *response_body : std::string(); LOG(ERROR) << "Failed to initialize referral" << ", error: " << referral_init_loader_->NetError() << ", response code: " << response_code - << ", payload: " << *response_body + << ", payload: " << safe_response_body << ", url: " << referral_init_loader_->GetFinalURL().spec(); return; } @@ -210,10 +214,12 @@ void BraveReferralsService::OnReferralFinalizationCheckLoadComplete( ->headers->response_code(); if (referral_finalization_check_loader_->NetError() != net::OK || response_code < 200 || response_code > 299) { + const std::string safe_response_body = + response_body ? *response_body : std::string(); LOG(ERROR) << "Failed to perform referral finalization check" << ", error: " << referral_finalization_check_loader_->NetError() << ", response code: " << response_code - << ", payload: " << *response_body << ", url: " + << ", payload: " << safe_response_body << ", url: " << referral_finalization_check_loader_->GetFinalURL().spec(); return; } From a52d41527af9562b2e94d989c0f493237702bf52 Mon Sep 17 00:00:00 2001 From: Emerick Rogul Date: Mon, 24 Sep 2018 13:23:11 -0400 Subject: [PATCH 12/13] Add laptop-updates-staging to network delegate whitelist --- browser/net/brave_static_redirect_network_delegate_helper.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/browser/net/brave_static_redirect_network_delegate_helper.cc b/browser/net/brave_static_redirect_network_delegate_helper.cc index 83aad25c4934..3fc8d9ba1f33 100644 --- a/browser/net/brave_static_redirect_network_delegate_helper.cc +++ b/browser/net/brave_static_redirect_network_delegate_helper.cc @@ -35,6 +35,11 @@ int OnBeforeURLRequest_StaticRedirectWork( static std::vector allowed_patterns({ // Brave updates URLPattern(URLPattern::SCHEME_HTTPS, "https://go-updater.brave.com/*"), + // Brave updates staging + // In the future, we may want to exclude the value of the + // BRAVE_REFERRALS_SERVER environment variable rather than + // hardcoding the server name here + URLPattern(URLPattern::SCHEME_HTTPS, "https://laptop-updates-staging.herokuapp.com/*"), // CRX file download URLPattern(URLPattern::SCHEME_HTTPS, "https://brave-core-ext.s3.brave.com/release/*"), // We do allow redirects to the Google update server for extensions we don't support From c87b146a675757b3d37cda665e58a0f938b2f6c5 Mon Sep 17 00:00:00 2001 From: Emerick Rogul Date: Tue, 25 Sep 2018 11:37:28 -0400 Subject: [PATCH 13/13] Add a randomized 0-10 minute delay when fetching referral headers We normally fetch every 24 hours, this will add a random delay to prevent the server from being able to correlate these requests as coming from the same user. --- browser/referrals/brave_referrals_service.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/browser/referrals/brave_referrals_service.cc b/browser/referrals/brave_referrals_service.cc index 8603bc490a38..a5f7cba3ed75 100644 --- a/browser/referrals/brave_referrals_service.cc +++ b/browser/referrals/brave_referrals_service.cc @@ -10,6 +10,7 @@ #include "base/json/json_reader.h" #include "base/json/json_writer.h" #include "base/path_service.h" +#include "base/rand_util.h" #include "base/strings/string_util.h" #include "base/sys_info.h" #include "base/task/post_task.h" @@ -93,7 +94,9 @@ void BraveReferralsService::Start() { DCHECK(!fetch_referral_headers_timer_); fetch_referral_headers_timer_ = std::make_unique(); fetch_referral_headers_timer_->Start( - FROM_HERE, base::TimeDelta::FromSeconds(kFetchReferralHeadersFrequency), + FROM_HERE, + base::TimeDelta::FromSeconds(kFetchReferralHeadersFrequency + + base::RandInt(0, 60 * 10)), this, &BraveReferralsService::OnFetchReferralHeadersTimerFired); DCHECK(fetch_referral_headers_timer_->IsRunning());