Merge pull request #16080 from brave/android_safebrowsing_safetynet

Android safebrowsing safetynet
This commit is contained in:
Serg
2022-11-29 13:34:34 -05:00
committed by GitHub
18 changed files with 400 additions and 7 deletions
+2
View File
@@ -3,6 +3,7 @@ import("//build/config/android/rules.gni")
declare_args() {
brave_android_developer_options_code = ""
brave_safebrowsing_api_key = ""
}
java_cpp_enum("brave_android_java_enums_srcjar") {
@@ -17,5 +18,6 @@ java_cpp_template("brave_config_java") {
defines = [
"BRAVE_ANDROID_DEVELOPER_OPTIONS_CODE=\"$brave_android_developer_options_code\"",
"BRAVE_ANDROID_P3A_ENABLED=$brave_p3a_enabled",
"BRAVE_SAFEBROWSING_API_KEY=\"$brave_safebrowsing_api_key\"",
]
}
+1
View File
@@ -277,6 +277,7 @@ brave_java_sources = [
"../../brave/android/java/org/chromium/chrome/browser/rewards/BraveRewardsTipFailureFragment.java",
"../../brave/android/java/org/chromium/chrome/browser/rewards/BraveRewardsTippingPanelFragment.java",
"../../brave/android/java/org/chromium/chrome/browser/safe_browsing/settings/BraveStandardProtectionSettingsFragment.java",
"../../brave/android/java/org/chromium/chrome/browser/safe_browsing/settings/NoGooglePlayServicesDialog.java",
"../../brave/android/java/org/chromium/chrome/browser/searchwidget/SearchWidgetProviderActivity.java",
"../../brave/android/java/org/chromium/chrome/browser/set_default_browser/BraveSetDefaultBrowserUtils.java",
"../../brave/android/java/org/chromium/chrome/browser/set_default_browser/OnBraveSetDefaultBrowserListener.java",
@@ -16,6 +16,7 @@ public abstract class BraveFeatureList {
public static final String BRAVE_BACKGROUND_VIDEO_PLAYBACK = "BraveBackgroundVideoPlayback";
public static final String BRAVE_BACKGROUND_VIDEO_PLAYBACK_INTERNAL =
"brave-background-video-playback";
public static final String BRAVE_ANDROID_SAFE_BROWSING = "BraveAndroidSafeBrowsing";
public static final String BRAVE_VPN_LINK_SUBSCRIPTION_ANDROID_UI =
"BraveVPNLinkSubscriptionAndroidUI";
}
@@ -80,6 +80,7 @@ import org.chromium.chrome.R;
import org.chromium.chrome.browser.ApplicationLifetime;
import org.chromium.chrome.browser.BraveAdFreeCalloutDialogFragment;
import org.chromium.chrome.browser.BraveAdaptiveCaptchaUtils;
import org.chromium.chrome.browser.BraveConfig;
import org.chromium.chrome.browser.BraveFeatureUtil;
import org.chromium.chrome.browser.BraveHelper;
import org.chromium.chrome.browser.BraveRelaunchUtils;
@@ -146,6 +147,8 @@ import org.chromium.chrome.browser.privacy.settings.BravePrivacySettings;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.rate.RateDialogFragment;
import org.chromium.chrome.browser.rate.RateUtils;
import org.chromium.chrome.browser.safe_browsing.SafeBrowsingBridge;
import org.chromium.chrome.browser.safe_browsing.SafeBrowsingState;
import org.chromium.chrome.browser.set_default_browser.BraveSetDefaultBrowserUtils;
import org.chromium.chrome.browser.set_default_browser.OnBraveSetDefaultBrowserListener;
import org.chromium.chrome.browser.settings.BraveNewsPreferences;
@@ -182,6 +185,8 @@ import org.chromium.chrome.browser.vpn.wireguard.WireguardConfigUtils;
import org.chromium.components.browser_ui.settings.SettingsLauncher;
import org.chromium.components.embedder_support.util.UrlConstants;
import org.chromium.components.embedder_support.util.UrlUtilities;
import org.chromium.components.safe_browsing.BraveSafeBrowsingApiHandler;
import org.chromium.components.safe_browsing.SafeBrowsingApiBridge;
import org.chromium.components.search_engines.TemplateUrl;
import org.chromium.components.user_prefs.UserPrefs;
import org.chromium.content_public.browser.WebContents;
@@ -204,7 +209,8 @@ import java.util.concurrent.CopyOnWriteArrayList;
@JNINamespace("chrome::android")
public abstract class BraveActivity<C extends ChromeActivityComponent> extends ChromeActivity
implements BrowsingDataBridge.OnClearBrowsingDataListener, BraveVpnObserver,
OnBraveSetDefaultBrowserListener, ConnectionErrorHandler, PrefObserver {
OnBraveSetDefaultBrowserListener, ConnectionErrorHandler, PrefObserver,
BraveSafeBrowsingApiHandler.BraveSafeBrowsingApiHandlerDelegate {
public static final String ADD_FUNDS_URL = "brave://rewards/#add-funds";
public static final String BRAVE_REWARDS_SETTINGS_URL = "brave://rewards/";
public static final String BRAVE_REWARDS_SETTINGS_WALLET_VERIFICATION_URL =
@@ -235,6 +241,8 @@ public abstract class BraveActivity<C extends ChromeActivityComponent> extends C
private static final List<String> yandexRegions =
Arrays.asList("AM", "AZ", "BY", "KG", "KZ", "MD", "RU", "TJ", "TM", "UZ");
private BraveSafeBrowsingApiHandler mBraveSafeBrowsingApiHandler;
private String mPurchaseToken = "";
private String mProductId = "";
private boolean mIsVerification;
@@ -293,6 +301,15 @@ public abstract class BraveActivity<C extends ChromeActivityComponent> extends C
}
updateWalletBadgeVisibility();
}
boolean safeBrowsingFlagEnabled =
ChromeFeatureList.isEnabled(BraveFeatureList.BRAVE_ANDROID_SAFE_BROWSING);
boolean safeBrowsingPrefEnabled =
SafeBrowsingBridge.getSafeBrowsingState() != SafeBrowsingState.NO_SAFE_BROWSING;
if (safeBrowsingFlagEnabled && safeBrowsingPrefEnabled) {
mBraveSafeBrowsingApiHandler.initSafeBrowsing();
} else if (!safeBrowsingFlagEnabled && safeBrowsingPrefEnabled) {
SafeBrowsingBridge.setSafeBrowsingState(SafeBrowsingState.NO_SAFE_BROWSING);
}
}
@Override
@@ -765,6 +782,18 @@ public abstract class BraveActivity<C extends ChromeActivityComponent> extends C
PostTask.postTask(
TaskTraits.BEST_EFFORT_MAY_BLOCK, () -> { BraveStatsUtil.removeShareStatsFile(); });
if (mBraveSafeBrowsingApiHandler == null) {
mBraveSafeBrowsingApiHandler =
new BraveSafeBrowsingApiHandler(this, BraveConfig.SAFEBROWSING_API_KEY, this);
SafeBrowsingApiBridge.setHandler(mBraveSafeBrowsingApiHandler);
SafeBrowsingApiBridge.ensureInitialized();
}
}
@Override
public void onPause() {
super.onPause();
mBraveSafeBrowsingApiHandler.shutdownSafeBrowsing();
}
@Override
@@ -788,6 +817,11 @@ public abstract class BraveActivity<C extends ChromeActivityComponent> extends C
maybeSolveAdaptiveCaptcha();
}
@Override
public void turnSafeBrowsingOff() {
SafeBrowsingBridge.setSafeBrowsingState(SafeBrowsingState.NO_SAFE_BROWSING);
}
public void maybeSolveAdaptiveCaptcha() {
String captchaID = UserPrefs.get(Profile.getLastUsedRegularProfile())
.getString(BravePref.SCHEDULED_CAPTCHA_ID);
@@ -13,11 +13,13 @@ import androidx.preference.ListPreference;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import org.chromium.base.BraveFeatureList;
import org.chromium.base.ContextUtils;
import org.chromium.base.Log;
import org.chromium.brave_shields.mojom.CookieListOptInPageAndroidHandler;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.BraveConfig;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.metrics.UmaSessionStats;
import org.chromium.chrome.browser.preferences.BravePref;
import org.chromium.chrome.browser.preferences.BravePrefServiceBridge;
@@ -27,6 +29,7 @@ import org.chromium.chrome.browser.preferences.website.BraveShieldsContentSettin
import org.chromium.chrome.browser.privacy.settings.PrivacyPreferencesManagerImpl;
import org.chromium.chrome.browser.privacy.settings.PrivacySettings;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.safe_browsing.settings.NoGooglePlayServicesDialog;
import org.chromium.chrome.browser.settings.BraveDialogPreference;
import org.chromium.chrome.browser.settings.BravePreferenceDialogFragment;
import org.chromium.chrome.browser.settings.BraveWebrtcPolicyPreference;
@@ -38,6 +41,7 @@ import org.chromium.components.browser_ui.settings.ChromeSwitchPreference;
import org.chromium.components.browser_ui.settings.SettingsUtils;
import org.chromium.components.prefs.PrefService;
import org.chromium.components.user_prefs.UserPrefs;
import org.chromium.gms.ChromiumPlayServicesAvailability;
import org.chromium.mojo.bindings.ConnectionErrorHandler;
import org.chromium.mojo.system.MojoException;
@@ -276,7 +280,23 @@ public class BravePrivacySettings extends PrivacySettings implements ConnectionE
removePreferenceIfPresent(PREF_SYNC_AND_SERVICES_LINK);
removePreferenceIfPresent(PREF_NETWORK_PREDICTIONS);
removePreferenceIfPresent(PREF_PRIVACY_SANDBOX);
removePreferenceIfPresent(PREF_SAFE_BROWSING);
if (!ChromeFeatureList.isEnabled(BraveFeatureList.BRAVE_ANDROID_SAFE_BROWSING)) {
removePreferenceIfPresent(PREF_SAFE_BROWSING);
} else {
Preference preference = getPreferenceScreen().findPreference(PREF_SAFE_BROWSING);
if (preference != null) {
preference.setOnPreferenceClickListener((pref) -> {
if (!ChromiumPlayServicesAvailability.isGooglePlayServicesAvailable(
getActivity())) {
NoGooglePlayServicesDialog.create(getContext()).show();
// Don't show the menu if Google Play Services are not available
return true;
}
return false;
});
}
}
if (mCookieListOptInPageAndroidHandler != null) {
mCookieListOptInPageAndroidHandler.shouldShowDialog(shouldShowDialog -> {
@@ -0,0 +1,66 @@
/* Copyright (c) 2022 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/. */
package org.chromium.chrome.browser.safe_browsing.settings;
import android.content.Context;
import android.content.res.Resources;
import org.chromium.components.browser_ui.modaldialog.AppModalPresenter;
import org.chromium.ui.modaldialog.DialogDismissalCause;
import org.chromium.ui.modaldialog.ModalDialogManager;
import org.chromium.ui.modaldialog.ModalDialogManager.ModalDialogType;
import org.chromium.ui.modaldialog.ModalDialogProperties;
import org.chromium.ui.modaldialog.ModalDialogProperties.Controller;
import org.chromium.ui.modelutil.PropertyModel;
/**
* Dialog to notify that the user is not protected by Safe Browsing as Google Play Services are not
* available.
*/
public class NoGooglePlayServicesDialog {
private Context mContext;
private ModalDialogManager mManager;
private PropertyModel mModel;
public static NoGooglePlayServicesDialog create(Context context) {
return new NoGooglePlayServicesDialog(context);
}
private NoGooglePlayServicesDialog(Context context) {
mContext = context;
}
/** Show this dialog in the context of its enclosing activity. */
public void show() {
Resources resources = mContext.getResources();
PropertyModel.Builder builder =
new PropertyModel.Builder(ModalDialogProperties.ALL_KEYS)
.with(ModalDialogProperties.CONTROLLER, makeController())
.with(ModalDialogProperties.TITLE, resources,
R.string.safe_browsing_no_google_play_services_dialog_title)
.with(ModalDialogProperties.MESSAGE_PARAGRAPH_1,
resources.getString(
R.string.safe_browsing_no_google_play_services_dialog_message))
.with(ModalDialogProperties.POSITIVE_BUTTON_TEXT, resources, R.string.ok);
mModel = builder.build();
mManager = new ModalDialogManager(new AppModalPresenter(mContext), ModalDialogType.APP);
mManager.showDialog(mModel, ModalDialogType.APP);
}
private Controller makeController() {
return new ModalDialogProperties.Controller() {
@Override
public void onClick(PropertyModel model, int buttonType) {
mManager.dismissDialog(mModel, DialogDismissalCause.POSITIVE_BUTTON_CLICKED);
}
@Override
public void onDismiss(PropertyModel model, int dismissalCause) {
mManager.destroy();
}
};
}
}
+15 -1
View File
@@ -58,6 +58,7 @@
#if BUILDFLAG(IS_ANDROID)
#include "brave/browser/android/preferences/features.h"
#include "brave/browser/android/safe_browsing/features.h"
#endif
using brave_shields::features::kBraveAdblockCnameUncloaking;
@@ -83,6 +84,7 @@ using ntp_background_images::features::kBraveNTPSuperReferralWallpaper;
#if BUILDFLAG(IS_ANDROID)
using preferences::features::kBraveBackgroundVideoPlayback;
using safe_browsing::features::kBraveAndroidSafeBrowsing;
#endif
namespace flag_descriptions {
@@ -400,6 +402,10 @@ constexpr char kBraveBackgroundVideoPlaybackDescription[] =
"Enables play audio from video in background when tab is not active or "
"device screen is turned off. Try to switch to desktop mode if this "
"feature is not working.";
constexpr char kBraveAndroidSafeBrowsingName[] = "Safe Browsing";
constexpr char kBraveAndroidSafeBrowsingDescription[] =
"Enables Google Safe Browsing for determining whether a URL has been "
"marked as a known threat.";
#endif
} // namespace
@@ -563,8 +569,15 @@ constexpr char kBraveBackgroundVideoPlaybackDescription[] =
flag_descriptions::kBraveBackgroundVideoPlaybackDescription, \
kOsAndroid, \
FEATURE_VALUE_TYPE(kBraveBackgroundVideoPlayback)},
#define BRAVE_SAFE_BROWSING_ANDROID \
{"brave-safe-browsing", \
flag_descriptions::kBraveAndroidSafeBrowsingName, \
flag_descriptions::kBraveAndroidSafeBrowsingDescription, \
kOsAndroid, \
FEATURE_VALUE_TYPE(kBraveAndroidSafeBrowsing)},
#else
#define BRAVE_BACKGROUND_VIDEO_PLAYBACK_ANDROID
#define BRAVE_SAFE_BROWSING_ANDROID
#endif // BUILDFLAG(IS_ANDROID)
#define BRAVE_ABOUT_FLAGS_FEATURE_ENTRIES \
@@ -727,4 +740,5 @@ constexpr char kBraveBackgroundVideoPlaybackDescription[] =
BRAVE_FEDERATED_FEATURE_ENTRIES \
PLAYLIST_FEATURE_ENTRIES \
BRAVE_VERTICAL_TABS_FEATURE_ENTRY \
BRAVE_BACKGROUND_VIDEO_PLAYBACK_ANDROID
BRAVE_BACKGROUND_VIDEO_PLAYBACK_ANDROID \
BRAVE_SAFE_BROWSING_ANDROID
+1
View File
@@ -17,6 +17,7 @@ source_set("android_browser_process") {
deps = [
"//base",
"//brave/browser/android/preferences",
"//brave/browser/android/safe_browsing",
"//brave/browser/brave_ads/android:jni_headers",
"//brave/build/android:jni_headers",
"//brave/components/brave_ads/browser",
+15
View File
@@ -0,0 +1,15 @@
# Copyright (c) 2022 The Brave Authors. All rights reserved.
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at https://mozilla.org/MPL/2.0/.
import("//build/config/android/rules.gni")
source_set("safe_browsing") {
sources = [
"features.cc",
"features.h",
]
deps = [ "//base" ]
}
+18
View File
@@ -0,0 +1,18 @@
/* Copyright (c) 2022 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/. */
#include "brave/browser/android/safe_browsing/features.h"
#include "base/feature_list.h"
namespace safe_browsing {
namespace features {
BASE_FEATURE(kBraveAndroidSafeBrowsing,
"BraveAndroidSafeBrowsing",
base::FEATURE_DISABLED_BY_DEFAULT);
} // namespace features
} // namespace safe_browsing
+19
View File
@@ -0,0 +1,19 @@
/* Copyright (c) 2022 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/. */
#ifndef BRAVE_BROWSER_ANDROID_SAFE_BROWSING_FEATURES_H_
#define BRAVE_BROWSER_ANDROID_SAFE_BROWSING_FEATURES_H_
#include "base/feature_list.h"
namespace safe_browsing {
namespace features {
BASE_DECLARE_FEATURE(kBraveAndroidSafeBrowsing);
} // namespace features
} // namespace safe_browsing
#endif // BRAVE_BROWSER_ANDROID_SAFE_BROWSING_FEATURES_H_
@@ -3309,6 +3309,12 @@ If you don't accept this request, VPN will not reconnect and your internet conne
<message name="IDS_LINK_SUBSCRIPTION_DIALOG_TEXT" desc="Brave vpn link subscription dialog text">
Your Brave VPN subscription can protect up to 5 devices, across Android, iOS, and desktop. Just link your Google Play subscription to your Brave account.
</message>
<message name="IDS_SAFE_BROWSING_NO_GOOGLE_PLAY_SERVICES_DIALOG_TITLE" desc="Brave no Google Play Services dialog title">
Cannot enable Safe Browsing
</message>
<message name="IDS_SAFE_BROWSING_NO_GOOGLE_PLAY_SERVICES_DIALOG_MESSAGE" desc="Brave no Google Play Services dialog message">
Safe Browsing has been disabled on your device. To enable it, ensure that Google Play Services is installed and that it's up to date.
</message>
</messages>
</release>
</grit>
+1
View File
@@ -25,6 +25,7 @@ brave_chrome_java_deps = [
"//brave/components/brave_today/common:mojom_java",
"//brave/components/brave_wallet/common:mojom_java",
"//brave/components/browser_ui/site_settings/android:java",
"//brave/components/safe_browsing/android:brave_safe_browsing_java",
"//brave/components/variations/android:java",
"//brave/third_party/android_deps:com_airbnb_android_java",
"//brave/third_party/android_deps:com_android_billingclient_java",
@@ -16,8 +16,14 @@ public class BraveConfig {
#endif
#if defined(BRAVE_ANDROID_P3A_ENABLED)
public static final boolean P3A_ENABLED = BRAVE_ANDROID_P3A_ENABLED;
public static final boolean P3A_ENABLED = BRAVE_ANDROID_P3A_ENABLED;
#else
public static final boolean P3A_ENABLED = false;
public static final boolean P3A_ENABLED = false;
#endif
#if defined(BRAVE_SAFEBROWSING_API_KEY)
public static final String SAFEBROWSING_API_KEY = BRAVE_SAFEBROWSING_API_KEY;
#else
public static final String SAFEBROWSING_API_KEY = "";
#endif
}
+6
View File
@@ -170,6 +170,7 @@ const Config = function () {
this.extraGnArgs = {}
this.extraGnGenOpts = getNPMConfig(['brave_extra_gn_gen_opts']) || ''
this.extraNinjaOpts = []
this.braveAndroidSafeBrowsingApiKey = getNPMConfig(['brave_safebrowsing_api_key']) || ''
this.braveSafetyNetApiKey = getNPMConfig(['brave_safetynet_api_key']) || ''
this.braveAndroidDeveloperOptionsCode = getNPMConfig(['brave_android_developer_options_code']) || ''
this.braveAndroidKeystorePath = getNPMConfig(['brave_android_keystore_path'])
@@ -468,6 +469,7 @@ Config.prototype.buildArgs = function () {
args.brave_android_developer_options_code = this.braveAndroidDeveloperOptionsCode
args.brave_safetynet_api_key = this.braveSafetyNetApiKey
args.brave_safebrowsing_api_key = this.braveAndroidSafeBrowsingApiKey
args.enable_widevine = false
args.safe_browsing_mode = 2
@@ -718,6 +720,10 @@ Config.prototype.update = function (options) {
this.braveGoogleApiKey = options.brave_google_api_key
}
if (options.brave_safebrowsing_api_key) {
this.braveAndroidSafeBrowsingApiKey = options.brave_safebrowsing_api_key
}
if (options.brave_safetynet_api_key) {
this.braveSafetyNetApiKey = options.brave_safetynet_api_key
}
@@ -5,6 +5,7 @@
#include "base/feature_override.h"
#include "brave/browser/android/preferences/features.h"
#include "brave/browser/android/safe_browsing/features.h"
#include "brave/components/brave_rewards/common/features.h"
#include "brave/components/brave_search_conversion/features.h"
#include "brave/components/brave_today/common/features.h"
@@ -17,10 +18,11 @@
&brave_rewards::features::kBraveRewards, \
&brave_search_conversion::features::kOmniboxBanner, \
&brave_today::features::kBraveNewsFeature, \
&brave_vpn::features::kBraveVPNLinkSubscriptionAndroidUI, \
&brave_vpn::features::kBraveVPNLinkSubscriptionAndroidUI,\
&brave_wallet::features::kNativeBraveWalletFeature, \
&brave_wallet::features::kBraveWalletSolanaFeature, \
&preferences::features::kBraveBackgroundVideoPlayback
&preferences::features::kBraveBackgroundVideoPlayback, \
&safe_browsing::features::kBraveAndroidSafeBrowsing
// clang-format on
#include "src/chrome/browser/flags/android/chrome_feature_list.cc"
+19
View File
@@ -0,0 +1,19 @@
# Copyright (c) 2022 The Brave Authors. All rights reserved.
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at https://mozilla.org/MPL/2.0/.
import("//build/config/android/config.gni")
import("//build/config/android/rules.gni")
android_library("brave_safe_browsing_java") {
deps = [
"//base:base_java",
"//brave/third_party/android_deps:google_play_services_safetynet_java",
"//build/android:build_java",
"//components/safe_browsing/android:safe_browsing_java",
"//third_party/android_deps:google_play_services_basement_java",
"//third_party/android_deps:google_play_services_tasks_java",
]
sources = [ "java/src/org/chromium/components/safe_browsing/BraveSafeBrowsingApiHandler.java" ]
}
@@ -0,0 +1,162 @@
/* Copyright (c) 2022 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/. */
package org.chromium.components.safe_browsing;
import android.app.Activity;
import android.content.pm.ApplicationInfo;
import com.google.android.gms.common.api.ApiException;
import com.google.android.gms.common.api.CommonStatusCodes;
import com.google.android.gms.safetynet.SafeBrowsingThreat;
import com.google.android.gms.safetynet.SafetyNet;
import com.google.android.gms.safetynet.SafetyNetApi;
import com.google.android.gms.safetynet.SafetyNetStatusCodes;
import com.google.android.gms.tasks.OnSuccessListener;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.chromium.base.ContextUtils;
import org.chromium.base.Log;
public class BraveSafeBrowsingApiHandler implements SafeBrowsingApiHandler {
private static final long DEFAULT_CHECK_DELTA = 10;
private static final String SAFE_METADATA = "{}";
private static final String TAG = "BraveSafeBrowsingApiHandler";
public interface BraveSafeBrowsingApiHandlerDelegate {
default void turnSafeBrowsingOff() {}
}
private Observer mObserver;
private Activity mActivity;
private String mApiKey;
private boolean mInitialized;
private int mTriesCount;
private BraveSafeBrowsingApiHandlerDelegate mBraveSafeBrowsingApiHandlerDelegate;
public BraveSafeBrowsingApiHandler(Activity activity, String apiKey,
BraveSafeBrowsingApiHandlerDelegate braveSafeBrowsingApiHandlerDelegate) {
mActivity = activity;
mApiKey = apiKey;
mTriesCount = 0;
mBraveSafeBrowsingApiHandlerDelegate = braveSafeBrowsingApiHandlerDelegate;
assert mBraveSafeBrowsingApiHandlerDelegate
!= null : "BraveSafeBrowsingApiHandlerDelegate has to be initialized";
}
@Override
public boolean init(Observer observer) {
mObserver = observer;
return true;
}
@Override
public void startUriLookup(final long callbackId, String uri, int[] threatsOfInterest) {
if (mActivity == null) {
return;
}
mTriesCount++;
if (!mInitialized) {
initSafeBrowsing();
}
SafetyNet.getClient(ContextUtils.getApplicationContext())
.lookupUri(uri, mApiKey, threatsOfInterest)
.addOnSuccessListener(mActivity,
sbResponse -> {
mTriesCount = 0;
try {
String metadata = SAFE_METADATA;
if (!sbResponse.getDetectedThreats().isEmpty()) {
JSONArray jsonArray = new JSONArray();
for (int i = 0; i < sbResponse.getDetectedThreats().size();
i++) {
JSONObject jsonObj = new JSONObject();
jsonObj.put("threat_type",
String.valueOf(sbResponse.getDetectedThreats()
.get(i)
.getThreatType()));
jsonArray.put(jsonObj);
}
JSONObject finalObj = new JSONObject();
finalObj.put("matches", jsonArray);
metadata = finalObj.toString();
}
if (mObserver != null) {
mObserver.onUrlCheckDone(callbackId, SafeBrowsingResult.SUCCESS,
metadata, DEFAULT_CHECK_DELTA);
}
} catch (JSONException e) {
}
})
.addOnFailureListener(mActivity, e -> {
// An error occurred while communicating with the service.
if (e instanceof ApiException) {
// An error with the Google Play Services API contains some
// additional details.
ApiException apiException = (ApiException) e;
if (isDebuggable()) {
Log.d(TAG,
"Error: "
+ CommonStatusCodes.getStatusCodeString(
apiException.getStatusCode())
+ ", code: " + apiException.getStatusCode());
}
if (apiException.getStatusCode() == CommonStatusCodes.API_NOT_CONNECTED) {
// That means that device doesn't have Google Play Services API.
// Delegate is used to turn off safe browsing option as every request is
// delayed when it's turned on and not working
mBraveSafeBrowsingApiHandlerDelegate.turnSafeBrowsingOff();
}
// Note: If the status code, apiException.getStatusCode(),
// is SafetyNetStatusCodes.SAFE_BROWSING_API_NOT_INITIALIZED,
// you need to call initSafeBrowsing(). It means either you
// haven't called initSafeBrowsing() before or that it needs
// to be called again due to an internal error.
if (mTriesCount <= 1
&& apiException.getStatusCode()
== SafetyNetStatusCodes.SAFE_BROWSING_API_NOT_INITIALIZED) {
initSafeBrowsing();
startUriLookup(callbackId, uri, threatsOfInterest);
}
} else {
// A different, unknown type of error occurred.
if (isDebuggable()) {
Log.d(TAG, "Error: " + e.getMessage());
}
}
mTriesCount = 0;
});
}
@Override
public boolean startAllowlistLookup(final String uri, int threatType) {
return false;
}
public void initSafeBrowsing() {
SafetyNet.getClient(mActivity).initSafeBrowsing();
mInitialized = true;
}
public void shutdownSafeBrowsing() {
if (!mInitialized) {
return;
}
SafetyNet.getClient(ContextUtils.getApplicationContext()).shutdownSafeBrowsing();
}
private boolean isDebuggable() {
if (mActivity == null) {
return false;
}
return 0 != (mActivity.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE);
}
}