diff --git a/android/brave_java_sources.gni b/android/brave_java_sources.gni index 47ee1520dfdb..a0ce169ca488 100644 --- a/android/brave_java_sources.gni +++ b/android/brave_java_sources.gni @@ -218,6 +218,8 @@ brave_java_sources = [ "../../brave/android/java/org/chromium/chrome/browser/util/ImageUtils.java", "../../brave/android/java/org/chromium/chrome/browser/util/PackageUtils.java", "../../brave/android/java/org/chromium/chrome/browser/util/TabUtils.java", + "../../brave/android/java/org/chromium/chrome/browser/vpn/BraveVpnNativeWorker.java", + "../../brave/android/java/org/chromium/chrome/browser/vpn/BraveVpnObserver.java", "../../brave/android/java/org/chromium/chrome/browser/widget/crypto/binance/BinanceAccountBalance.java", "../../brave/android/java/org/chromium/chrome/browser/widget/crypto/binance/BinanceActivity.java", "../../brave/android/java/org/chromium/chrome/browser/widget/crypto/binance/BinanceBuyFragment.java", diff --git a/android/java/org/chromium/chrome/browser/app/BraveActivity.java b/android/java/org/chromium/chrome/browser/app/BraveActivity.java index 7352a391feb1..bfe46fb24cc1 100644 --- a/android/java/org/chromium/chrome/browser/app/BraveActivity.java +++ b/android/java/org/chromium/chrome/browser/app/BraveActivity.java @@ -101,6 +101,7 @@ import org.chromium.chrome.browser.util.BraveDbUtil; import org.chromium.chrome.browser.util.BraveReferrer; import org.chromium.chrome.browser.util.PackageUtils; +import org.chromium.chrome.browser.vpn.BraveVpnNativeWorker; import org.chromium.chrome.browser.widget.crypto.binance.BinanceAccountBalance; import org.chromium.chrome.browser.widget.crypto.binance.BinanceWidgetManager; import org.chromium.components.bookmarks.BookmarkId; @@ -418,6 +419,7 @@ public void finishNativeInitialization() { } checkSetDefaultBrowserModal(); checkFingerPrintingOnUpgrade(); + BraveVpnNativeWorker.getInstance().getAllServerRegions(); } private void checkFingerPrintingOnUpgrade() { diff --git a/android/java/org/chromium/chrome/browser/vpn/BraveVpnNativeWorker.java b/android/java/org/chromium/chrome/browser/vpn/BraveVpnNativeWorker.java new file mode 100644 index 000000000000..cb916c6bc056 --- /dev/null +++ b/android/java/org/chromium/chrome/browser/vpn/BraveVpnNativeWorker.java @@ -0,0 +1,142 @@ +/** + * Copyright (c) 2021 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +package org.chromium.chrome.browser.vpn; + +import org.chromium.base.annotations.CalledByNative; +import org.chromium.base.annotations.JNINamespace; +import org.chromium.chrome.browser.vpn.BraveVpnObserver; + +import java.util.ArrayList; +import java.util.List; + +@JNINamespace("chrome::android") +public class BraveVpnNativeWorker { + private long mNativeBraveVpnNativeWorker; + private static final Object lock = new Object(); + private static BraveVpnNativeWorker instance; + + private List mObservers; + + public static BraveVpnNativeWorker getInstance() { + synchronized (lock) { + if (instance == null) { + instance = new BraveVpnNativeWorker(); + instance.init(); + } + } + return instance; + } + + private BraveVpnNativeWorker() { + mObservers = new ArrayList(); + } + + private void init() { + if (mNativeBraveVpnNativeWorker == 0) { + nativeInit(); + } + } + + @Override + protected void finalize() { + destroy(); + } + + private void destroy() { + if (mNativeBraveVpnNativeWorker != 0) { + nativeDestroy(mNativeBraveVpnNativeWorker); + mNativeBraveVpnNativeWorker = 0; + } + } + + public void addObserver(BraveVpnObserver observer) { + synchronized (lock) { + mObservers.add(observer); + } + } + + public void removeObserver(BraveVpnObserver observer) { + synchronized (lock) { + mObservers.remove(observer); + } + } + + @CalledByNative + private void setNativePtr(long nativePtr) { + assert mNativeBraveVpnNativeWorker == 0; + mNativeBraveVpnNativeWorker = nativePtr; + } + + @CalledByNative + public void onGetAllServerRegions(String jsonServerRegions, boolean isSuccess) { + for (BraveVpnObserver observer : mObservers) { + observer.onGetAllServerRegions(jsonServerRegions, isSuccess); + } + } + + @CalledByNative + public void onGetTimezonesForRegions(String jsonTimezones, boolean isSuccess) { + for (BraveVpnObserver observer : mObservers) { + observer.onGetTimezonesForRegions(jsonTimezones, isSuccess); + } + } + + @CalledByNative + public void onGetHostnamesForRegion(String jsonHostnames, boolean isSuccess) { + for (BraveVpnObserver observer : mObservers) { + observer.onGetHostnamesForRegion(jsonHostnames, isSuccess); + } + } + + @CalledByNative + public void onGetSubscriberCredential(String subscriberCredential, boolean isSuccess) { + for (BraveVpnObserver observer : mObservers) { + observer.onGetSubscriberCredential(subscriberCredential, isSuccess); + } + } + + @CalledByNative + public void onVerifyPurchaseToken(String jsonResponse, boolean isSuccess) { + for (BraveVpnObserver observer : mObservers) { + observer.onVerifyPurchaseToken(jsonResponse, isSuccess); + } + } + + public void getAllServerRegions() { + nativeGetAllServerRegions(mNativeBraveVpnNativeWorker); + } + + public void getTimezonesForRegions() { + nativeGetTimezonesForRegions(mNativeBraveVpnNativeWorker); + } + + public void getHostnamesForRegion(String region) { + nativeGetHostnamesForRegion(mNativeBraveVpnNativeWorker, region); + } + + public void getSubscriberCredential( + String productType, String productId, String validationMethod, String purchaseToken) { + nativeGetSubscriberCredential(mNativeBraveVpnNativeWorker, productType, productId, + validationMethod, purchaseToken); + } + + public void verifyPurchaseToken(String purchaseToken, String productId, String productType) { + nativeVerifyPurchaseToken( + mNativeBraveVpnNativeWorker, purchaseToken, productId, productType); + } + + private native void nativeInit(); + private native void nativeDestroy(long nativeBraveVpnNativeWorker); + private native void nativeGetAllServerRegions(long nativeBraveVpnNativeWorker); + private native void nativeGetTimezonesForRegions(long nativeBraveVpnNativeWorker); + private native void nativeGetHostnamesForRegion(long nativeBraveVpnNativeWorker, String region); + private native void nativeGetSubscriberCredential(long nativeBraveVpnNativeWorker, + String productType, String productId, String validationMethod, String purchaseToken); + private native void nativeVerifyPurchaseToken(long nativeBraveVpnNativeWorker, + String purchaseToken, String productId, String productType); +} diff --git a/android/java/org/chromium/chrome/browser/vpn/BraveVpnObserver.java b/android/java/org/chromium/chrome/browser/vpn/BraveVpnObserver.java new file mode 100644 index 000000000000..752e09fd1041 --- /dev/null +++ b/android/java/org/chromium/chrome/browser/vpn/BraveVpnObserver.java @@ -0,0 +1,13 @@ +/* Copyright (c) 2021 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ +package org.chromium.chrome.browser.vpn; + +public interface BraveVpnObserver { + default public void onGetAllServerRegions(String jsonServerRegions, boolean isSuccess){}; + default public void onGetTimezonesForRegions(String jsonTimezones, boolean isSuccess){}; + default public void onGetHostnamesForRegion(String jsonHostnames, boolean isSuccess){}; + default public void onGetSubscriberCredential(String subscriberCredential, boolean isSuccess){}; + default public void onVerifyPurchaseToken(String jsonResponse, boolean isSuccess){}; +} diff --git a/browser/brave_vpn/android/brave_vpn_native_worker.cc b/browser/brave_vpn/android/brave_vpn_native_worker.cc new file mode 100644 index 000000000000..87b6bb626e6f --- /dev/null +++ b/browser/brave_vpn/android/brave_vpn_native_worker.cc @@ -0,0 +1,173 @@ +/* Copyright (c) 2021 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "brave/browser/brave_vpn/android/brave_vpn_native_worker.h" + +#include "base/android/jni_android.h" +#include "base/android/jni_array.h" +#include "base/android/jni_string.h" +#include "base/bind.h" +#include "base/json/json_writer.h" +#include "base/values.h" +#include "brave/browser/brave_vpn/brave_vpn_service_factory.h" +#include "brave/build/android/jni_headers/BraveVpnNativeWorker_jni.h" +#include "brave/components/brave_vpn/brave_vpn_service.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/profiles/profile_manager.h" + +namespace { + +BraveVpnService* GetBraveVpnService() { + return BraveVpnServiceFactory::GetForProfile( + ProfileManager::GetActiveUserProfile()->GetOriginalProfile()); +} + +} // namespace + +namespace chrome { +namespace android { + +BraveVpnNativeWorker::BraveVpnNativeWorker( + JNIEnv* env, + const base::android::JavaRef& obj) + : weak_java_brave_vpn_native_worker_(env, obj), weak_factory_(this) { + Java_BraveVpnNativeWorker_setNativePtr(env, obj, + reinterpret_cast(this)); +} + +BraveVpnNativeWorker::~BraveVpnNativeWorker() {} + +void BraveVpnNativeWorker::Destroy( + JNIEnv* env, + const base::android::JavaParamRef& jcaller) { + delete this; +} + +void BraveVpnNativeWorker::GetAllServerRegions( + JNIEnv* env, + const base::android::JavaParamRef& jcaller) { + BraveVpnService* brave_vpn_service = GetBraveVpnService(); + if (brave_vpn_service) { + brave_vpn_service->GetAllServerRegions( + base::BindOnce(&BraveVpnNativeWorker::OnGetAllServerRegions, + weak_factory_.GetWeakPtr())); + } +} + +void BraveVpnNativeWorker::OnGetAllServerRegions( + const std::string& server_regions_json, + bool success) { + JNIEnv* env = base::android::AttachCurrentThread(); + Java_BraveVpnNativeWorker_onGetAllServerRegions( + env, weak_java_brave_vpn_native_worker_.get(env), + base::android::ConvertUTF8ToJavaString(env, server_regions_json), + success); +} + +void BraveVpnNativeWorker::GetTimezonesForRegions( + JNIEnv* env, + const base::android::JavaParamRef& jcaller) { + BraveVpnService* brave_vpn_service = GetBraveVpnService(); + if (brave_vpn_service) { + brave_vpn_service->GetTimezonesForRegions( + base::BindOnce(&BraveVpnNativeWorker::OnGetTimezonesForRegions, + weak_factory_.GetWeakPtr())); + } +} + +void BraveVpnNativeWorker::OnGetTimezonesForRegions( + const std::string& timezones_json, + bool success) { + JNIEnv* env = base::android::AttachCurrentThread(); + Java_BraveVpnNativeWorker_onGetTimezonesForRegions( + env, weak_java_brave_vpn_native_worker_.get(env), + base::android::ConvertUTF8ToJavaString(env, timezones_json), success); +} + +void BraveVpnNativeWorker::GetHostnamesForRegion( + JNIEnv* env, + const base::android::JavaParamRef& jcaller, + const base::android::JavaParamRef& region) { + BraveVpnService* brave_vpn_service = GetBraveVpnService(); + if (brave_vpn_service) { + brave_vpn_service->GetHostnamesForRegion( + base::BindOnce(&BraveVpnNativeWorker::OnGetHostnamesForRegion, + weak_factory_.GetWeakPtr()), + base::android::ConvertJavaStringToUTF8(env, region)); + } +} + +void BraveVpnNativeWorker::OnGetHostnamesForRegion( + const std::string& hostnames_json, + bool success) { + JNIEnv* env = base::android::AttachCurrentThread(); + Java_BraveVpnNativeWorker_onGetHostnamesForRegion( + env, weak_java_brave_vpn_native_worker_.get(env), + base::android::ConvertUTF8ToJavaString(env, hostnames_json), success); +} + +void BraveVpnNativeWorker::GetSubscriberCredential( + JNIEnv* env, + const base::android::JavaParamRef& jcaller, + const base::android::JavaParamRef& product_type, + const base::android::JavaParamRef& product_id, + const base::android::JavaParamRef& validation_method, + const base::android::JavaParamRef& purchase_token) { + BraveVpnService* brave_vpn_service = GetBraveVpnService(); + if (brave_vpn_service) { + brave_vpn_service->GetSubscriberCredential( + base::BindOnce(&BraveVpnNativeWorker::OnGetSubscriberCredential, + weak_factory_.GetWeakPtr()), + base::android::ConvertJavaStringToUTF8(env, product_type), + base::android::ConvertJavaStringToUTF8(env, product_id), + base::android::ConvertJavaStringToUTF8(env, validation_method), + base::android::ConvertJavaStringToUTF8(env, purchase_token)); + } +} + +void BraveVpnNativeWorker::OnGetSubscriberCredential( + const std::string& subscriber_credential, + bool success) { + JNIEnv* env = base::android::AttachCurrentThread(); + Java_BraveVpnNativeWorker_onGetSubscriberCredential( + env, weak_java_brave_vpn_native_worker_.get(env), + base::android::ConvertUTF8ToJavaString(env, subscriber_credential), + success); +} + +void BraveVpnNativeWorker::VerifyPurchaseToken( + JNIEnv* env, + const base::android::JavaParamRef& jcaller, + const base::android::JavaParamRef& purchase_token, + const base::android::JavaParamRef& product_id, + const base::android::JavaParamRef& product_type) { + BraveVpnService* brave_vpn_service = GetBraveVpnService(); + if (brave_vpn_service) { + brave_vpn_service->VerifyPurchaseToken( + base::BindOnce(&BraveVpnNativeWorker::OnVerifyPurchaseToken, + weak_factory_.GetWeakPtr()), + base::android::ConvertJavaStringToUTF8(env, purchase_token), + base::android::ConvertJavaStringToUTF8(env, product_id), + base::android::ConvertJavaStringToUTF8(env, product_type)); + } +} + +void BraveVpnNativeWorker::OnVerifyPurchaseToken( + const std::string& json_response, + bool success) { + JNIEnv* env = base::android::AttachCurrentThread(); + Java_BraveVpnNativeWorker_onVerifyPurchaseToken( + env, weak_java_brave_vpn_native_worker_.get(env), + base::android::ConvertUTF8ToJavaString(env, json_response), success); +} + +static void JNI_BraveVpnNativeWorker_Init( + JNIEnv* env, + const base::android::JavaParamRef& jcaller) { + new BraveVpnNativeWorker(env, jcaller); +} + +} // namespace android +} // namespace chrome diff --git a/browser/brave_vpn/android/brave_vpn_native_worker.h b/browser/brave_vpn/android/brave_vpn_native_worker.h new file mode 100644 index 000000000000..eee9590f6e66 --- /dev/null +++ b/browser/brave_vpn/android/brave_vpn_native_worker.h @@ -0,0 +1,75 @@ +/* Copyright (c) 2021 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_BROWSER_BRAVE_VPN_ANDROID_BRAVE_VPN_NATIVE_WORKER_H_ +#define BRAVE_BROWSER_BRAVE_VPN_ANDROID_BRAVE_VPN_NATIVE_WORKER_H_ + +#include +#include + +#include "base/android/jni_weak_ref.h" +#include "base/memory/weak_ptr.h" + +namespace chrome { +namespace android { +class BraveVpnNativeWorker { + public: + BraveVpnNativeWorker(JNIEnv* env, const base::android::JavaRef& obj); + ~BraveVpnNativeWorker(); + + BraveVpnNativeWorker(const BraveVpnNativeWorker&) = delete; + BraveVpnNativeWorker& operator=(const BraveVpnNativeWorker&) = delete; + + void Destroy(JNIEnv* env, + const base::android::JavaParamRef& jcaller); + + void GetAllServerRegions(JNIEnv* env, + const base::android::JavaParamRef& jcaller); + + void OnGetAllServerRegions(const std::string& server_regions_json, + bool success); + + void GetTimezonesForRegions( + JNIEnv* env, + const base::android::JavaParamRef& jcaller); + + void OnGetTimezonesForRegions(const std::string& timezones_json, + bool success); + + void GetHostnamesForRegion( + JNIEnv* env, + const base::android::JavaParamRef& jcaller, + const base::android::JavaParamRef& region); + + void OnGetHostnamesForRegion(const std::string& hostname_json, bool success); + + void GetSubscriberCredential( + JNIEnv* env, + const base::android::JavaParamRef& jcaller, + const base::android::JavaParamRef& product_type, + const base::android::JavaParamRef& product_id, + const base::android::JavaParamRef& validation_method, + const base::android::JavaParamRef& purchase_token); + + void OnGetSubscriberCredential(const std::string& subscriber_credential, + bool success); + + void VerifyPurchaseToken( + JNIEnv* env, + const base::android::JavaParamRef& jcaller, + const base::android::JavaParamRef& purchase_token, + const base::android::JavaParamRef& product_id, + const base::android::JavaParamRef& product_type); + + void OnVerifyPurchaseToken(const std::string& json_response, bool success); + + private: + JavaObjectWeakGlobalRef weak_java_brave_vpn_native_worker_; + base::WeakPtrFactory weak_factory_; +}; +} // namespace android +} // namespace chrome + +#endif // BRAVE_BROWSER_BRAVE_VPN_ANDROID_BRAVE_VPN_NATIVE_WORKER_H_ diff --git a/browser/brave_vpn/brave_vpn_service_factory.cc b/browser/brave_vpn/brave_vpn_service_factory.cc new file mode 100644 index 000000000000..5d2acc7d9e5d --- /dev/null +++ b/browser/brave_vpn/brave_vpn_service_factory.cc @@ -0,0 +1,44 @@ +/* Copyright (c) 2021 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "brave/browser/brave_vpn/brave_vpn_service_factory.h" + +#include "brave/components/brave_vpn/brave_vpn_service.h" +#include "chrome/browser/profiles/incognito_helpers.h" +#include "chrome/browser/profiles/profile.h" +#include "components/keyed_service/content/browser_context_dependency_manager.h" +#include "content/public/browser/browser_context.h" +#include "content/public/browser/storage_partition.h" + +// static +BraveVpnServiceFactory* BraveVpnServiceFactory::GetInstance() { + return base::Singleton::get(); +} + +// static +BraveVpnService* BraveVpnServiceFactory::GetForProfile(Profile* profile) { + return static_cast( + GetInstance()->GetServiceForBrowserContext(profile, true)); +} + +BraveVpnServiceFactory::BraveVpnServiceFactory() + : BrowserContextKeyedServiceFactory( + "BraveVpnService", + BrowserContextDependencyManager::GetInstance()) {} + +BraveVpnServiceFactory::~BraveVpnServiceFactory() = default; + +KeyedService* BraveVpnServiceFactory::BuildServiceInstanceFor( + content::BrowserContext* context) const { + auto* default_storage_partition = context->GetDefaultStoragePartition(); + auto shared_url_loader_factory = + default_storage_partition->GetURLLoaderFactoryForBrowserProcess(); + return new BraveVpnService(shared_url_loader_factory); +} + +content::BrowserContext* BraveVpnServiceFactory::GetBrowserContextToUse( + content::BrowserContext* context) const { + return chrome::GetBrowserContextRedirectedInIncognito(context); +} diff --git a/browser/brave_vpn/brave_vpn_service_factory.h b/browser/brave_vpn/brave_vpn_service_factory.h new file mode 100644 index 000000000000..739f9d8ddba0 --- /dev/null +++ b/browser/brave_vpn/brave_vpn_service_factory.h @@ -0,0 +1,36 @@ +/* Copyright (c) 2021 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_BROWSER_BRAVE_VPN_BRAVE_VPN_SERVICE_FACTORY_H_ +#define BRAVE_BROWSER_BRAVE_VPN_BRAVE_VPN_SERVICE_FACTORY_H_ + +#include "base/memory/singleton.h" +#include "components/keyed_service/content/browser_context_keyed_service_factory.h" + +class BraveVpnService; +class Profile; + +class BraveVpnServiceFactory : public BrowserContextKeyedServiceFactory { + public: + static BraveVpnService* GetForProfile(Profile* profile); + static BraveVpnServiceFactory* GetInstance(); + + BraveVpnServiceFactory(const BraveVpnServiceFactory&) = delete; + BraveVpnServiceFactory& operator=(const BraveVpnServiceFactory&) = delete; + + private: + friend struct base::DefaultSingletonTraits; + + BraveVpnServiceFactory(); + ~BraveVpnServiceFactory() override; + + // BrowserContextKeyedServiceFactory overrides: + KeyedService* BuildServiceInstanceFor( + content::BrowserContext* context) const override; + content::BrowserContext* GetBrowserContextToUse( + content::BrowserContext* context) const override; +}; + +#endif // BRAVE_BROWSER_BRAVE_VPN_BRAVE_VPN_SERVICE_FACTORY_H_ diff --git a/browser/brave_vpn/sources.gni b/browser/brave_vpn/sources.gni new file mode 100644 index 000000000000..e47b6a675192 --- /dev/null +++ b/browser/brave_vpn/sources.gni @@ -0,0 +1,32 @@ +# Copyright (c) 2021 The Brave Authors. All rights reserved. +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this file, +# You can obtain one at http://mozilla.org/MPL/2.0/. + +import("//brave/components/brave_vpn/buildflags/buildflags.gni") + +brave_browser_brave_vpn_sources = [] +brave_browser_brave_vpn_deps = [] + +if (enable_brave_vpn) { + brave_browser_brave_vpn_sources += [ + "//brave/browser/brave_vpn/brave_vpn_service_factory.cc", + "//brave/browser/brave_vpn/brave_vpn_service_factory.h", + ] + + brave_browser_brave_vpn_deps += [ + "//base", + "//brave/components/brave_vpn", + "//chrome/browser/profiles:profile", + "//components/keyed_service/content", + "//content/public/browser", + ] + + if (is_android) { + brave_browser_brave_vpn_sources += [ + "//brave/browser/brave_vpn/android/brave_vpn_native_worker.cc", + "//brave/browser/brave_vpn/android/brave_vpn_native_worker.h", + ] + brave_browser_brave_vpn_deps += [ "//brave/build/android:jni_headers" ] + } +} diff --git a/browser/sources.gni b/browser/sources.gni index b1f41eece09e..9323703d7216 100644 --- a/browser/sources.gni +++ b/browser/sources.gni @@ -8,6 +8,7 @@ import("//brave/browser/binance/sources.gni") import("//brave/browser/brave_rewards/sources.gni") import("//brave/browser/brave_shields/sources.gni") import("//brave/browser/brave_stats/sources.gni") +import("//brave/browser/brave_vpn/sources.gni") import("//brave/browser/browsing_data/sources.gni") import("//brave/browser/component_updater/sources.gni") import("//brave/browser/crypto_dot_com/sources.gni") @@ -330,6 +331,7 @@ brave_chrome_browser_defines = [] brave_chrome_browser_sources += brave_browser_autocomplete_sources brave_chrome_browser_sources += brave_browser_binance_sources +brave_chrome_browser_sources += brave_browser_brave_vpn_sources brave_chrome_browser_sources += brave_browser_brave_rewards_sources brave_chrome_browser_sources += brave_browser_brave_shields_sources brave_chrome_browser_sources += brave_browser_brave_stats_updater_sources @@ -350,6 +352,7 @@ brave_chrome_browser_sources += brave_browser_themes_sources brave_chrome_browser_deps += brave_browser_autocomplete_deps brave_chrome_browser_deps += brave_browser_binance_deps +brave_chrome_browser_deps += brave_browser_brave_vpn_deps brave_chrome_browser_deps += brave_browser_brave_rewards_deps brave_chrome_browser_deps += brave_browser_brave_shields_deps brave_chrome_browser_deps += brave_browser_brave_stats_updater_deps diff --git a/build/android/BUILD.gn b/build/android/BUILD.gn index f781cc4788cf..a511d03e03f8 100755 --- a/build/android/BUILD.gn +++ b/build/android/BUILD.gn @@ -181,6 +181,7 @@ generate_jni("jni_headers") { "//brave/android/java/org/chromium/chrome/browser/preferences/website/BraveShieldsContentSettings.java", "//brave/android/java/org/chromium/chrome/browser/settings/developer/BraveQAPreferences.java", "//brave/android/java/org/chromium/chrome/browser/signin/BraveSigninManager.java", + "//brave/android/java/org/chromium/chrome/browser/vpn/BraveVpnNativeWorker.java", "//brave/android/java/org/chromium/chrome/browser/widget/crypto/binance/BinanceNativeWorker.java", ] diff --git a/components/api_request_helper/api_request_helper.cc b/components/api_request_helper/api_request_helper.cc index 2089b382d4e9..751119edfe55 100644 --- a/components/api_request_helper/api_request_helper.cc +++ b/components/api_request_helper/api_request_helper.cc @@ -23,12 +23,14 @@ APIRequestHelper::APIRequestHelper( APIRequestHelper::~APIRequestHelper() {} -void APIRequestHelper::Request(const std::string& method, - const GURL& url, - const std::string& payload, - const std::string& payload_content_type, - bool auto_retry_on_network_change, - ResultCallback callback) { +void APIRequestHelper::Request( + const std::string& method, + const GURL& url, + const std::string& payload, + const std::string& payload_content_type, + bool auto_retry_on_network_change, + ResultCallback callback, + const std::map& headers) { auto request = std::make_unique(); request->url = url; request->load_flags = net::LOAD_BYPASS_CACHE | net::LOAD_DISABLE_CACHE | @@ -36,6 +38,11 @@ void APIRequestHelper::Request(const std::string& method, request->credentials_mode = network::mojom::CredentialsMode::kOmit; request->method = method; + if (!headers.empty()) { + for (auto entry : headers) + request->headers.SetHeader(entry.first, entry.second); + } + auto url_loader = network::SimpleURLLoader::Create(std::move(request), annotation_tag_); if (!payload.empty()) { diff --git a/components/api_request_helper/api_request_helper.h b/components/api_request_helper/api_request_helper.h index 85849113d742..3b62d0638de3 100644 --- a/components/api_request_helper/api_request_helper.h +++ b/components/api_request_helper/api_request_helper.h @@ -39,7 +39,8 @@ class APIRequestHelper { const std::string& payload, const std::string& payload_content_type, bool auto_retry_on_network_change, - ResultCallback callback); + ResultCallback callback, + const std::map& headers = {}); private: APIRequestHelper(const APIRequestHelper&) = delete; diff --git a/components/brave_vpn/BUILD.gn b/components/brave_vpn/BUILD.gn index c0393e9690eb..e4e65502cffc 100644 --- a/components/brave_vpn/BUILD.gn +++ b/components/brave_vpn/BUILD.gn @@ -9,11 +9,18 @@ static_library("brave_vpn") { "brave_vpn_connection_info.h", "brave_vpn_connection_manager.cc", "brave_vpn_connection_manager.h", + "brave_vpn_service.cc", + "brave_vpn_service.h", ] deps = [ ":brave_vpn_internal", "//base", + "//brave/components/api_request_helper:api_request_helper", + "//components/keyed_service/core", + "//net", + "//services/network/public/cpp", + "//url", ] libs = [] diff --git a/components/brave_vpn/DEPS b/components/brave_vpn/DEPS new file mode 100644 index 000000000000..fb9ef90d6215 --- /dev/null +++ b/components/brave_vpn/DEPS @@ -0,0 +1,8 @@ +include_rules = [ + "+services/network/public/cpp", + "+base", + "+components/keyed_service/core", + "+net", + "+url", + "+brave/components/api_request_helper", +] \ No newline at end of file diff --git a/components/brave_vpn/brave_vpn_service.cc b/components/brave_vpn/brave_vpn_service.cc new file mode 100644 index 000000000000..fba80b78e003 --- /dev/null +++ b/components/brave_vpn/brave_vpn_service.cc @@ -0,0 +1,183 @@ +/* Copyright (c) 2021 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "brave/components/brave_vpn/brave_vpn_service.h" + +#include "base/json/json_reader.h" +#include "base/json/json_writer.h" + +namespace { +constexpr char kVpnHost[] = "housekeeping.sudosecuritygroup.com"; + +constexpr char kAllServerRegions[] = "api/v1/servers/all-server-regions"; +constexpr char kTimezonesForRegions[] = + "api/v1.1/servers/timezones-for-regions"; +constexpr char kHostnameForRegion[] = "api/v1/servers/hostnames-for-region"; +constexpr char kCreateSubscriberCredential[] = + "api/v1/subscriber-credential/create"; +constexpr char kVerifyPurchaseToken[] = "api/v1.1/verify-purchase-token"; + +net::NetworkTrafficAnnotationTag GetNetworkTrafficAnnotationTag() { + return net::DefineNetworkTrafficAnnotation("brave_vpn_service", R"( + semantics { + sender: "Brave VPN Service" + description: + "This service is used to communicate with Guardian VPN apis" + "on behalf of the user interacting with the Brave VPN." + trigger: + "Triggered by user connecting the Brave VPN." + data: + "Servers, hosts and credentials for Brave VPN" + destination: WEBSITE + } + )"); +} + +GURL GetURLWithPath(const std::string& host, const std::string& path) { + return GURL(std::string(url::kHttpsScheme) + "://" + host).Resolve(path); +} + +std::string CreateJSONRequestBody(const base::Value& dict) { + std::string json; + base::JSONWriter::Write(dict, &json); + return json; +} + +std::string GetSubscriberCredentialFromJson(const std::string& json) { + base::JSONReader::ValueWithError value_with_error = + base::JSONReader::ReadAndReturnValueWithError( + json, base::JSONParserOptions::JSON_PARSE_RFC); + base::Optional& records_v = value_with_error.value; + if (!records_v) { + LOG(ERROR) << "Invalid response, could not parse JSON, JSON is: " << json; + return ""; + } + + const base::DictionaryValue* response_dict; + if (!records_v->GetAsDictionary(&response_dict)) { + return ""; + } + + const base::Value* subscriber_credential = + records_v->FindKey("subscriber-credential"); + return subscriber_credential == nullptr ? "" + : subscriber_credential->GetString(); +} + +} // namespace + +BraveVpnService::BraveVpnService( + scoped_refptr url_loader_factory) + : api_request_helper_(GetNetworkTrafficAnnotationTag(), + url_loader_factory) {} + +BraveVpnService::~BraveVpnService() = default; + +void BraveVpnService::OAuthRequest(const GURL& url, + const std::string& method, + const std::string& post_data, + bool set_app_ident, + URLRequestCallback callback) { + std::map headers; + if (set_app_ident) { + headers["GRD-App-Ident"] = "Brave-Client"; + } + + api_request_helper_.Request(method, url, post_data, "application/json", false, + std::move(callback), headers); +} + +void BraveVpnService::GetAllServerRegions(ResponseCallback callback) { + auto internal_callback = + base::BindOnce(&BraveVpnService::OnGetResponse, base::Unretained(this), + std::move(callback)); + GURL base_url = GetURLWithPath(kVpnHost, kAllServerRegions); + OAuthRequest(base_url, "GET", "", false, std::move(internal_callback)); +} + +void BraveVpnService::GetTimezonesForRegions(ResponseCallback callback) { + auto internal_callback = + base::BindOnce(&BraveVpnService::OnGetResponse, base::Unretained(this), + std::move(callback)); + GURL base_url = GetURLWithPath(kVpnHost, kTimezonesForRegions); + OAuthRequest(base_url, "GET", "", false, std::move(internal_callback)); +} + +void BraveVpnService::GetHostnamesForRegion(ResponseCallback callback, + const std::string& region) { + auto internal_callback = + base::BindOnce(&BraveVpnService::OnGetResponse, base::Unretained(this), + std::move(callback)); + GURL base_url = GetURLWithPath(kVpnHost, kHostnameForRegion); + base::Value dict(base::Value::Type::DICTIONARY); + dict.SetStringKey("region", region); + std::string request_body = CreateJSONRequestBody(dict); + OAuthRequest(base_url, "POST", request_body, false, + std::move(internal_callback)); +} + +void BraveVpnService::VerifyPurchaseToken(ResponseCallback callback, + const std::string& purchase_token, + const std::string& product_id, + const std::string& product_type) { + auto internal_callback = + base::BindOnce(&BraveVpnService::OnGetResponse, base::Unretained(this), + std::move(callback)); + GURL base_url = GetURLWithPath(kVpnHost, kVerifyPurchaseToken); + base::Value dict(base::Value::Type::DICTIONARY); + dict.SetStringKey("purchase-token", purchase_token); + dict.SetStringKey("product-id", product_id); + dict.SetStringKey("product-type", product_type); + std::string request_body = CreateJSONRequestBody(dict); + OAuthRequest(base_url, "POST", request_body, true, + std::move(internal_callback)); +} + +void BraveVpnService::OnGetResponse( + ResponseCallback callback, + int status, + const std::string& body, + const std::map& headers) { + std::string json_response; + bool success = status == 200; + if (success) { + json_response = body; + } + std::move(callback).Run(json_response, success); +} + +void BraveVpnService::GetSubscriberCredential( + ResponseCallback callback, + const std::string& product_type, + const std::string& product_id, + const std::string& validation_method, + const std::string& purchase_token) { + auto internal_callback = + base::BindOnce(&BraveVpnService::OnGetSubscriberCredential, + base::Unretained(this), std::move(callback)); + GURL base_url = GetURLWithPath(kVpnHost, kCreateSubscriberCredential); + base::Value dict(base::Value::Type::DICTIONARY); + dict.SetStringKey("product-type", product_type); + dict.SetStringKey("product-id", product_id); + dict.SetStringKey("validation-method", validation_method); + dict.SetStringKey("purchase-token", purchase_token); + std::string request_body = CreateJSONRequestBody(dict); + OAuthRequest(base_url, "POST", request_body, true, + std::move(internal_callback)); +} + +void BraveVpnService::OnGetSubscriberCredential( + ResponseCallback callback, + int status, + const std::string& body, + const std::map& headers) { + std::string subscriber_credential; + + bool success = status == 200; + if (success) { + subscriber_credential = GetSubscriberCredentialFromJson(body); + } + std::move(callback).Run(subscriber_credential, success); +} diff --git a/components/brave_vpn/brave_vpn_service.h b/components/brave_vpn/brave_vpn_service.h new file mode 100644 index 000000000000..11cc78743b0b --- /dev/null +++ b/components/brave_vpn/brave_vpn_service.h @@ -0,0 +1,76 @@ +/* Copyright (c) 2021 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_COMPONENTS_BRAVE_VPN_BRAVE_VPN_SERVICE_H_ +#define BRAVE_COMPONENTS_BRAVE_VPN_BRAVE_VPN_SERVICE_H_ + +#include +#include +#include +#include + +#include "base/bind.h" +#include "base/callback_forward.h" +#include "base/memory/scoped_refptr.h" +#include "brave/components/api_request_helper/api_request_helper.h" +#include "components/keyed_service/core/keyed_service.h" +#include "services/network/public/cpp/shared_url_loader_factory.h" +#include "url/gurl.h" + +namespace network { +class SharedURLLoaderFactory; +} // namespace network + +class BraveVpnService : public KeyedService { + public: + explicit BraveVpnService( + scoped_refptr url_loader_factory); + ~BraveVpnService() override; + + BraveVpnService(const BraveVpnService&) = delete; + BraveVpnService& operator=(const BraveVpnService&) = delete; + + using ResponseCallback = + base::OnceCallback; + + void GetAllServerRegions(ResponseCallback callback); + void GetTimezonesForRegions(ResponseCallback callback); + void GetHostnamesForRegion(ResponseCallback callback, + const std::string& region); + void GetSubscriberCredential(ResponseCallback callback, + const std::string& product_type, + const std::string& product_id, + const std::string& validation_method, + const std::string& purchase_token); + void VerifyPurchaseToken(ResponseCallback callback, + const std::string& purchase_token, + const std::string& product_id, + const std::string& product_type); + + private: + using URLRequestCallback = base::OnceCallback< + void(int, const std::string&, const std::map&)>; + + void OAuthRequest(const GURL& url, + const std::string& method, + const std::string& post_data, + bool set_app_ident, + URLRequestCallback callback); + + void OnGetResponse(ResponseCallback callback, + int status, + const std::string& body, + const std::map& headers); + + void OnGetSubscriberCredential( + ResponseCallback callback, + int status, + const std::string& body, + const std::map& headers); + + api_request_helper::APIRequestHelper api_request_helper_; +}; + +#endif // BRAVE_COMPONENTS_BRAVE_VPN_BRAVE_VPN_SERVICE_H_ diff --git a/components/brave_vpn/buildflags/buildflags.gni b/components/brave_vpn/buildflags/buildflags.gni index 30fad0e59825..72bb7725dc56 100644 --- a/components/brave_vpn/buildflags/buildflags.gni +++ b/components/brave_vpn/buildflags/buildflags.gni @@ -4,5 +4,5 @@ # You can obtain one at http://mozilla.org/MPL/2.0/. declare_args() { - enable_brave_vpn = is_win + enable_brave_vpn = is_win || is_android }