From e66c446dd55939538e2cc9e41aaeb73029dbfe7e Mon Sep 17 00:00:00 2001 From: Alex <256235273+alekspop26@users.noreply.github.com> Date: Thu, 4 Jun 2026 17:24:47 -0400 Subject: [PATCH] [VPN 2.0] Add BraveVpnServiceImpl V2 stubs (#36935) To add a new BraveVpnService implementation based on Architecture 2.0, which must co-exist with Architecture 1.0 for quite a while, we need to split service's interface and implementation. All the external components will keep accessing VPN service via the BraveVpnService interface, but the implementation mostly goes into BraveVpnServiceImpl. This change adds the second service implementation, BraveVpnServiceImpl, for Architecture 2.0. It will live in a "components/brave_vpn/browser/v2" subdirectory, but will eventually move into "components/brave_vpn/browser" once V1 implementation has been removed. Notable changes: - fully testable BraveVpnServiceImpl v2 stub implementation, in a dedicated "v2" namespace; - BraveVpnServiceFactory can now create a proper implementation based on the compile-time GN flags; - v1/v2 include isolation using DEPS include rules (so that the implementations can't depend on each other); - stub unit test for BraveVpnServiceImpl v2. Resolves https://github.com/brave/brave-browser/issues/54597 --- .../brave_vpn/brave_vpn_service_factory.cc | 18 ++- browser/sources.gni | 5 +- components/brave_vpn/browser/DEPS | 1 + components/brave_vpn/browser/v2/BUILD.gn | 32 +++++ components/brave_vpn/browser/v2/DEPS | 10 ++ .../browser/v2/brave_vpn_service_impl.cc | 60 +++++++++ .../browser/v2/brave_vpn_service_impl.h | 123 ++++++++++++++++++ .../v2/brave_vpn_service_impl_android.cc | 96 ++++++++++++++ .../v2/brave_vpn_service_impl_desktop.cc | 118 +++++++++++++++++ 9 files changed, 460 insertions(+), 3 deletions(-) create mode 100644 components/brave_vpn/browser/v2/BUILD.gn create mode 100644 components/brave_vpn/browser/v2/DEPS create mode 100644 components/brave_vpn/browser/v2/brave_vpn_service_impl.cc create mode 100644 components/brave_vpn/browser/v2/brave_vpn_service_impl.h create mode 100644 components/brave_vpn/browser/v2/brave_vpn_service_impl_android.cc create mode 100644 components/brave_vpn/browser/v2/brave_vpn_service_impl_desktop.cc diff --git a/browser/brave_vpn/brave_vpn_service_factory.cc b/browser/brave_vpn/brave_vpn_service_factory.cc index 632cf9cb3d8..539bd7ef207 100644 --- a/browser/brave_vpn/brave_vpn_service_factory.cc +++ b/browser/brave_vpn/brave_vpn_service_factory.cc @@ -39,10 +39,22 @@ #endif // IS_WIN #endif // ENABLE_BRAVE_VPN_V1 +#if BUILDFLAG(ENABLE_BRAVE_VPN_V2) +#include "brave/components/brave_vpn/browser/v2/brave_vpn_service_impl.h" +#endif // BUILDFLAG(ENABLE_BRAVE_VPN_V2) + namespace brave_vpn { namespace { -#if BUILDFLAG(ENABLE_BRAVE_VPN_V1) +#if BUILDFLAG(ENABLE_BRAVE_VPN_V2) + +std::unique_ptr BuildVpnService_V2( + content::BrowserContext* context) { + // Return stub implementation. + return std::make_unique(); +} + +#elif BUILDFLAG(ENABLE_BRAVE_VPN_V1) std::unique_ptr BuildVpnService_V1( content::BrowserContext* context) { @@ -102,7 +114,9 @@ std::unique_ptr BuildVpnService( if (!brave_vpn::IsAllowedForContext(context)) { return nullptr; } -#if BUILDFLAG(ENABLE_BRAVE_VPN_V1) +#if BUILDFLAG(ENABLE_BRAVE_VPN_V2) + return BuildVpnService_V2(context); +#elif BUILDFLAG(ENABLE_BRAVE_VPN_V1) return BuildVpnService_V1(context); #else NOTREACHED() << "No VPN implementation available"; diff --git a/browser/sources.gni b/browser/sources.gni index a7ed8be2a4d..7a563b62973 100644 --- a/browser/sources.gni +++ b/browser/sources.gni @@ -554,7 +554,10 @@ if (enable_brave_vpn) { } if (enable_brave_vpn_v2) { - brave_chrome_browser_deps += [ "//brave/third_party/boringtun" ] + brave_chrome_browser_deps += [ + "//brave/components/brave_vpn/browser/v2:browser", + "//brave/third_party/boringtun", + ] } if (is_android) { diff --git a/components/brave_vpn/browser/DEPS b/components/brave_vpn/browser/DEPS index a87ceab21eb..5334527a57d 100644 --- a/components/brave_vpn/browser/DEPS +++ b/components/brave_vpn/browser/DEPS @@ -1,4 +1,5 @@ include_rules = [ + "-components/brave_vpn/browser/v2", "+components/grit/brave_components_strings.h", "+components/keyed_service", "+components/prefs", diff --git a/components/brave_vpn/browser/v2/BUILD.gn b/components/brave_vpn/browser/v2/BUILD.gn new file mode 100644 index 00000000000..38d64fc7492 --- /dev/null +++ b/components/brave_vpn/browser/v2/BUILD.gn @@ -0,0 +1,32 @@ +# Copyright (c) 2026 The Brave Authors. All rights reserved. +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this file, +# You can obtain one at https://mozilla.org/MPL/2.0/. + +import("//brave/components/brave_vpn/common/buildflags/buildflags.gni") + +assert(enable_brave_vpn_v2) + +static_library("browser") { + sources = [ + "brave_vpn_service_impl.cc", + "brave_vpn_service_impl.h", + ] + + if (is_android) { + sources += [ "brave_vpn_service_impl_android.cc" ] + } else if (is_linux || is_mac || is_win) { + sources += [ "brave_vpn_service_impl_desktop.cc" ] + } + + public_deps = [ + "//brave/components/brave_vpn/browser", + "//brave/components/skus/browser", + "//brave/components/skus/common:mojom", + ] + + deps = [ + "//base", + "//brave/components/brave_vpn/common", + ] +} diff --git a/components/brave_vpn/browser/v2/DEPS b/components/brave_vpn/browser/v2/DEPS new file mode 100644 index 00000000000..b83a9b0d043 --- /dev/null +++ b/components/brave_vpn/browser/v2/DEPS @@ -0,0 +1,10 @@ +include_rules = [ + "-brave/components/brave_vpn/browser", + "-brave/components/brave_vpn/common", + "+brave/components/brave_vpn/browser/v2", + "+brave/components/brave_vpn/browser/brave_vpn_service.h", + "+brave/components/brave_vpn/common/brave_vpn_constants.h", + "+brave/components/brave_vpn/common/brave_vpn_utils.h", + "+brave/components/brave_vpn/common/buildflags", + "+brave/components/brave_vpn/common/mojom", +] diff --git a/components/brave_vpn/browser/v2/brave_vpn_service_impl.cc b/components/brave_vpn/browser/v2/brave_vpn_service_impl.cc new file mode 100644 index 00000000000..2d06054ca9d --- /dev/null +++ b/components/brave_vpn/browser/v2/brave_vpn_service_impl.cc @@ -0,0 +1,60 @@ +/* Copyright (c) 2026 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#include "brave/components/brave_vpn/browser/v2/brave_vpn_service_impl.h" + +#include "base/notimplemented.h" +#include "brave/components/skus/browser/skus_utils.h" + +namespace brave_vpn { +namespace v2 { + +BraveVpnServiceImpl::BraveVpnServiceImpl() + : connection_state_(mojom::ConnectionState::DISCONNECTED), + purchased_state_(mojom::PurchasedState::NOT_PURCHASED) {} + +BraveVpnServiceImpl::~BraveVpnServiceImpl() = default; + +bool BraveVpnServiceImpl::IsBraveVPNEnabled() const { + NOTIMPLEMENTED(); + return false; +} + +bool BraveVpnServiceImpl::IsPurchased() const { + NOTIMPLEMENTED(); + return purchased_state_ == mojom::PurchasedState::PURCHASED; +} + +void BraveVpnServiceImpl::ReloadPurchasedState() { + NOTIMPLEMENTED(); +} + +std::string BraveVpnServiceImpl::GetCurrentEnvironment() const { + NOTIMPLEMENTED(); + return skus::kEnvProduction; +} + +void BraveVpnServiceImpl::GetPurchasedState( + GetPurchasedStateCallback callback) { + NOTIMPLEMENTED(); + std::move(callback).Run( + mojom::PurchasedInfo::New(purchased_state_, std::nullopt)); +} + +void BraveVpnServiceImpl::LoadPurchasedState(const std::string& domain) { + NOTIMPLEMENTED(); +} + +void BraveVpnServiceImpl::GetAllRegions(GetAllRegionsCallback callback) { + NOTIMPLEMENTED(); + std::move(callback).Run({}); +} + +void BraveVpnServiceImpl::Shutdown() { + BraveVpnService::Shutdown(); +} + +} // namespace v2 +} // namespace brave_vpn diff --git a/components/brave_vpn/browser/v2/brave_vpn_service_impl.h b/components/brave_vpn/browser/v2/brave_vpn_service_impl.h new file mode 100644 index 00000000000..fc413a28da7 --- /dev/null +++ b/components/brave_vpn/browser/v2/brave_vpn_service_impl.h @@ -0,0 +1,123 @@ +/* Copyright (c) 2026 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_COMPONENTS_BRAVE_VPN_BROWSER_V2_BRAVE_VPN_SERVICE_IMPL_H_ +#define BRAVE_COMPONENTS_BRAVE_VPN_BROWSER_V2_BRAVE_VPN_SERVICE_IMPL_H_ + +#include "brave/components/brave_vpn/browser/brave_vpn_service.h" +#include "build/build_config.h" + +namespace brave_vpn { +namespace v2 { + +class BraveVpnServiceImpl : public BraveVpnService { + public: + BraveVpnServiceImpl(); + ~BraveVpnServiceImpl() override; + + BraveVpnServiceImpl(const BraveVpnServiceImpl&) = delete; + BraveVpnServiceImpl& operator=(const BraveVpnServiceImpl&) = delete; + + // BraveVpnService overrides: + // Implementation of public interface exposed to other components. + bool IsBraveVPNEnabled() const override; + bool IsPurchased() const override; + void ReloadPurchasedState() override; + std::string GetCurrentEnvironment() const override; + + // mojom::ServiceHandler overrides: + void GetPurchasedState(GetPurchasedStateCallback callback) override; + void LoadPurchasedState(const std::string& domain) override; + void GetAllRegions(GetAllRegionsCallback callback) override; + +#if !BUILDFLAG(IS_ANDROID) + // BraveVpnService overrides: + bool IsConnected() const override; + void ToggleConnection() override; + mojom::ConnectionState GetConnectionState() const override; + void RecordWidgetUsageMetrics(bool new_usage) override; + + // mojom::ServiceHandler overrides: + void GetConnectionState(GetConnectionStateCallback callback) override; + void Connect() override; + void Disconnect() override; + void GetSelectedRegion(GetSelectedRegionCallback callback) override; + void SetSelectedRegion(mojom::RegionPtr region) override; + void ClearSelectedRegion() override; + void GetProductUrls(GetProductUrlsCallback callback) override; + void CreateSupportTicket(const std::string& email, + const std::string& subject, + const std::string& body, + CreateSupportTicketCallback callback) override; + void GetSupportData(GetSupportDataCallback callback) override; + void ResetConnectionState() override; + void EnableOnDemand(bool enable) override; + void GetOnDemandState(GetOnDemandStateCallback callback) override; + void EnableSmartProxyRouting(bool enable) override; + void GetSmartProxyRoutingState( + GetSmartProxyRoutingStateCallback callback) override; +#else // !BUILDFLAG(IS_ANDROID) + // mojom::ServiceHandler overrides: + void GetPurchaseToken(GetPurchaseTokenCallback callback) override; + + // Implementation of public interface for Android native worker. + void GetTimezonesForRegions(ResponseCallback callback) override; + void GetHostnamesForRegion(ResponseCallback callback, + const std::string& region, + const std::string& region_precision) override; + void GetProfileCredentials(ResponseCallback callback, + const std::string& subscriber_credential, + const std::string& hostname) override; + void GetWireguardProfileCredentials(ResponseCallback callback, + const std::string& subscriber_credential, + const std::string& public_key, + const std::string& hostname) override; + void VerifyCredentials(ResponseCallback callback, + const std::string& hostname, + const std::string& client_id, + const std::string& subscriber_credential, + const std::string& api_auth_token) override; + void InvalidateCredentials(ResponseCallback callback, + const std::string& hostname, + const std::string& client_id, + const std::string& subscriber_credential, + const std::string& api_auth_token) override; + void VerifyPurchaseToken(ResponseCallback callback, + const std::string& purchase_token, + const std::string& product_id, + const std::string& product_type, + const std::string& bundle_id) override; + void GetSubscriberCredential(ResponseCallback callback, + const std::string& product_type, + const std::string& product_id, + const std::string& validation_method, + const std::string& purchase_token, + const std::string& bundle_id) override; + void GetSubscriberCredentialV12(ResponseCallback callback) override; + void RecordAllMetrics() override; + void RecordAndroidBackgroundP3A(int64_t session_start_time_ms, + int64_t session_end_time_ms) override; +#endif // BUILDFLAG(IS_ANDROID) + + private: + // KeyedService overrides: + void Shutdown() override; + + // BraveVpnService overrides: +#if !BUILDFLAG(IS_ANDROID) + void SetConnectionStateForTesting(mojom::ConnectionState state) override; + void SetPurchasedStateForTesting(const std::string& env, + mojom::PurchasedState state) override; +#endif // !BUILDFLAG(IS_ANDROID) + + private: + [[maybe_unused]] mojom::ConnectionState connection_state_; + mojom::PurchasedState purchased_state_; +}; + +} // namespace v2 +} // namespace brave_vpn + +#endif // BRAVE_COMPONENTS_BRAVE_VPN_BROWSER_V2_BRAVE_VPN_SERVICE_IMPL_H_ diff --git a/components/brave_vpn/browser/v2/brave_vpn_service_impl_android.cc b/components/brave_vpn/browser/v2/brave_vpn_service_impl_android.cc new file mode 100644 index 00000000000..82ae54c5afd --- /dev/null +++ b/components/brave_vpn/browser/v2/brave_vpn_service_impl_android.cc @@ -0,0 +1,96 @@ +/* Copyright (c) 2026 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#include "brave/components/brave_vpn/browser/v2/brave_vpn_service_impl.h" + +#include "base/notimplemented.h" + +namespace brave_vpn { +namespace v2 { + +void BraveVpnServiceImpl::GetPurchaseToken(GetPurchaseTokenCallback callback) { + NOTIMPLEMENTED(); + std::move(callback).Run({}); +} + +void BraveVpnServiceImpl::GetTimezonesForRegions(ResponseCallback callback) { + NOTIMPLEMENTED(); +} + +void BraveVpnServiceImpl::GetHostnamesForRegion( + ResponseCallback callback, + const std::string& region, + const std::string& region_precision) { + NOTIMPLEMENTED(); +} + +void BraveVpnServiceImpl::GetProfileCredentials( + ResponseCallback callback, + const std::string& subscriber_credential, + const std::string& hostname) { + NOTIMPLEMENTED(); +} + +void BraveVpnServiceImpl::GetWireguardProfileCredentials( + ResponseCallback callback, + const std::string& subscriber_credential, + const std::string& public_key, + const std::string& hostname) { + NOTIMPLEMENTED(); +} + +void BraveVpnServiceImpl::VerifyCredentials( + ResponseCallback callback, + const std::string& hostname, + const std::string& client_id, + const std::string& subscriber_credential, + const std::string& api_auth_token) { + NOTIMPLEMENTED(); +} + +void BraveVpnServiceImpl::InvalidateCredentials( + ResponseCallback callback, + const std::string& hostname, + const std::string& client_id, + const std::string& subscriber_credential, + const std::string& api_auth_token) { + NOTIMPLEMENTED(); +} + +void BraveVpnServiceImpl::VerifyPurchaseToken(ResponseCallback callback, + const std::string& purchase_token, + const std::string& product_id, + const std::string& product_type, + const std::string& bundle_id) { + NOTIMPLEMENTED(); +} + +void BraveVpnServiceImpl::GetSubscriberCredential( + ResponseCallback callback, + const std::string& product_type, + const std::string& product_id, + const std::string& validation_method, + const std::string& purchase_token, + const std::string& bundle_id) { + NOTIMPLEMENTED(); +} + +void BraveVpnServiceImpl::GetSubscriberCredentialV12( + ResponseCallback callback) { + NOTIMPLEMENTED(); +} + +void BraveVpnServiceImpl::RecordAllMetrics() { + NOTIMPLEMENTED(); +} + +void BraveVpnServiceImpl::RecordAndroidBackgroundP3A( + int64_t session_start_time_ms, + int64_t session_end_time_ms) { + NOTIMPLEMENTED(); +} + +} // namespace v2 +} // namespace brave_vpn diff --git a/components/brave_vpn/browser/v2/brave_vpn_service_impl_desktop.cc b/components/brave_vpn/browser/v2/brave_vpn_service_impl_desktop.cc new file mode 100644 index 00000000000..515a37219bd --- /dev/null +++ b/components/brave_vpn/browser/v2/brave_vpn_service_impl_desktop.cc @@ -0,0 +1,118 @@ +/* Copyright (c) 2026 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#include "base/notimplemented.h" +#include "brave/components/brave_vpn/browser/v2/brave_vpn_service_impl.h" +#include "brave/components/brave_vpn/common/brave_vpn_constants.h" +#include "brave/components/brave_vpn/common/brave_vpn_utils.h" + +namespace brave_vpn { +namespace v2 { + +bool BraveVpnServiceImpl::IsConnected() const { + NOTIMPLEMENTED(); + return connection_state_ == mojom::ConnectionState::CONNECTED && + IsPurchased(); +} + +void BraveVpnServiceImpl::ToggleConnection() { + NOTIMPLEMENTED(); +} + +mojom::ConnectionState BraveVpnServiceImpl::GetConnectionState() const { + NOTIMPLEMENTED(); + return connection_state_; +} + +void BraveVpnServiceImpl::RecordWidgetUsageMetrics(bool new_usage) { + NOTIMPLEMENTED(); +} + +void BraveVpnServiceImpl::GetConnectionState( + GetConnectionStateCallback callback) { + NOTIMPLEMENTED(); + std::move(callback).Run(connection_state_); +} + +void BraveVpnServiceImpl::Connect() { + NOTIMPLEMENTED(); +} + +void BraveVpnServiceImpl::Disconnect() { + NOTIMPLEMENTED(); +} + +void BraveVpnServiceImpl::GetSelectedRegion( + GetSelectedRegionCallback callback) { + NOTIMPLEMENTED(); + std::move(callback).Run({}); +} + +void BraveVpnServiceImpl::SetSelectedRegion(mojom::RegionPtr region) { + NOTIMPLEMENTED(); +} + +void BraveVpnServiceImpl::ClearSelectedRegion() { + NOTIMPLEMENTED(); +} + +void BraveVpnServiceImpl::GetProductUrls(GetProductUrlsCallback callback) { + NOTIMPLEMENTED(); + std::move(callback).Run(mojom::ProductUrls::New( + kFeedbackUrl, kAboutUrl, GetManageUrl(GetCurrentEnvironment()))); +} + +void BraveVpnServiceImpl::CreateSupportTicket( + const std::string& email, + const std::string& subject, + const std::string& body, + CreateSupportTicketCallback callback) { + NOTIMPLEMENTED(); + std::move(callback).Run(false, {}); +} + +void BraveVpnServiceImpl::GetSupportData(GetSupportDataCallback callback) { + NOTIMPLEMENTED(); + std::move(callback).Run({}, {}, {}, {}); +} + +void BraveVpnServiceImpl::ResetConnectionState() { + NOTIMPLEMENTED(); +} + +void BraveVpnServiceImpl::EnableOnDemand(bool /*enable*/) { + NOTIMPLEMENTED(); +} + +void BraveVpnServiceImpl::GetOnDemandState(GetOnDemandStateCallback callback) { + NOTIMPLEMENTED(); + std::move(callback).Run(false, false); +} + +void BraveVpnServiceImpl::EnableSmartProxyRouting(bool /*enable*/) { + NOTIMPLEMENTED(); +} + +void BraveVpnServiceImpl::GetSmartProxyRoutingState( + GetSmartProxyRoutingStateCallback callback) { + NOTIMPLEMENTED(); + std::move(callback).Run(false); +} + +void BraveVpnServiceImpl::SetConnectionStateForTesting( // IN-TEST + mojom::ConnectionState state) { + connection_state_ = state; + NotifyConnectionStateChanged(state); +} + +void BraveVpnServiceImpl::SetPurchasedStateForTesting( // IN-TEST + const std::string& env, + mojom::PurchasedState state) { + purchased_state_ = state; + NotifyPurchasedStateChanged(state, std::nullopt); +} + +} // namespace v2 +} // namespace brave_vpn