/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- * vim: ts=4 sw=4 expandtab: * 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.mozilla.geckoview; import android.annotation.SuppressLint; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; import androidx.annotation.AnyThread; import androidx.annotation.IntDef; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.UiThread; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Map; import org.mozilla.gecko.util.GeckoBundle; /** Content Blocking API to hold and control anti-tracking, cookie and Safe Browsing settings. */ @AnyThread public class ContentBlocking { /** {@link SafeBrowsingProvider} configuration for Google's legacy SafeBrowsing server. */ public static final SafeBrowsingProvider GOOGLE_LEGACY_SAFE_BROWSING_PROVIDER = SafeBrowsingProvider.withName("google") .version("2.2") .lists( "goog-badbinurl-shavar", "goog-downloadwhite-digest256", "goog-phish-shavar", "googpub-phish-shavar", "goog-malware-shavar", "goog-unwanted-shavar") .updateUrl( "https://safebrowsing.google.com/safebrowsing/downloads?client=SAFEBROWSING_ID&appver=%MAJOR_VERSION%&pver=2.2&key=%GOOGLE_SAFEBROWSING_API_KEY%") .getHashUrl( "https://safebrowsing.google.com/safebrowsing/gethash?client=SAFEBROWSING_ID&appver=%MAJOR_VERSION%&pver=2.2") .reportUrl("https://safebrowsing.google.com/safebrowsing/diagnostic?site=") .reportPhishingMistakeUrl("https://%LOCALE%.phish-error.mozilla.com/?url=") .reportMalwareMistakeUrl("https://%LOCALE%.malware-error.mozilla.com/?url=") .advisoryUrl("https://developers.google.com/safe-browsing/v4/advisory") .advisoryName("Google Safe Browsing") .build(); /** {@link SafeBrowsingProvider} configuration for Google's SafeBrowsing server. */ public static final SafeBrowsingProvider GOOGLE_SAFE_BROWSING_PROVIDER = SafeBrowsingProvider.withName("google4") .version("4") .lists( "goog-badbinurl-proto", "goog-downloadwhite-proto", "goog-phish-proto", "googpub-phish-proto", "goog-malware-proto", "goog-unwanted-proto", "goog-harmful-proto") .updateUrl( "https://safebrowsing.googleapis.com/v4/threatListUpdates:fetch?$ct=application/x-protobuf&key=%GOOGLE_SAFEBROWSING_API_KEY%&$httpMethod=POST") .getHashUrl( "https://safebrowsing.googleapis.com/v4/fullHashes:find?$ct=application/x-protobuf&key=%GOOGLE_SAFEBROWSING_API_KEY%&$httpMethod=POST") .reportUrl("https://safebrowsing.google.com/safebrowsing/diagnostic?site=") .reportPhishingMistakeUrl("https://%LOCALE%.phish-error.mozilla.com/?url=") .reportMalwareMistakeUrl("https://%LOCALE%.malware-error.mozilla.com/?url=") .advisoryUrl("https://developers.google.com/safe-browsing/v4/advisory") .advisoryName("Google Safe Browsing") .dataSharingUrl( "https://safebrowsing.googleapis.com/v4/threatHits?$ct=application/x-protobuf&key=%GOOGLE_SAFEBROWSING_API_KEY%&$httpMethod=POST") .dataSharingEnabled(false) .build(); // This class shouldn't be instantiated protected ContentBlocking() {} @AnyThread public static class Settings extends RuntimeSettings { private final Map mSafeBrowsingProviders = new HashMap<>(); private static final SafeBrowsingProvider[] DEFAULT_PROVIDERS = { ContentBlocking.GOOGLE_LEGACY_SAFE_BROWSING_PROVIDER, ContentBlocking.GOOGLE_SAFE_BROWSING_PROVIDER }; @AnyThread public static class Builder extends RuntimeSettings.Builder { @Override protected @NonNull Settings newSettings(final @Nullable Settings settings) { return new Settings(settings); } /** * Set custom safe browsing providers. * * @param providers one or more custom providers. * @return This Builder instance. * @see SafeBrowsingProvider */ public @NonNull Builder safeBrowsingProviders( final @NonNull SafeBrowsingProvider... providers) { getSettings().setSafeBrowsingProviders(providers); return this; } /** * Set the safe browsing table for phishing threats. * * @param safeBrowsingPhishingTable one or more lists for safe browsing phishing. * @return This Builder instance. * @see SafeBrowsingProvider */ public @NonNull Builder safeBrowsingPhishingTable( final @NonNull String[] safeBrowsingPhishingTable) { getSettings().setSafeBrowsingPhishingTable(safeBrowsingPhishingTable); return this; } /** * Set the safe browsing table for malware threats. * * @param safeBrowsingMalwareTable one or more lists for safe browsing malware. * @return This Builder instance. * @see SafeBrowsingProvider */ public @NonNull Builder safeBrowsingMalwareTable( final @NonNull String[] safeBrowsingMalwareTable) { getSettings().setSafeBrowsingMalwareTable(safeBrowsingMalwareTable); return this; } /** * Set anti-tracking categories. * * @param cat The categories of resources that should be blocked. Use one or more of the * {@link ContentBlocking.AntiTracking} flags. * @return This Builder instance. */ public @NonNull Builder antiTracking(final @CBAntiTracking int cat) { getSettings().setAntiTracking(cat); return this; } /** * Set safe browsing categories. * * @param cat The categories of resources that should be blocked. Use one or more of the * {@link ContentBlocking.SafeBrowsing} flags. * @return This Builder instance. */ public @NonNull Builder safeBrowsing(final @CBSafeBrowsing int cat) { getSettings().setSafeBrowsing(cat); return this; } /** * Set cookie storage behavior. * * @param behavior The storage behavior that should be applied. Use one of the {@link * CookieBehavior} flags. * @return The Builder instance. */ public @NonNull Builder cookieBehavior(final @CBCookieBehavior int behavior) { getSettings().setCookieBehavior(behavior); return this; } /** * Set cookie storage behavior in private browsing mode. * * @param behavior The storage behavior that should be applied. Use one of the {@link * CookieBehavior} flags. * @return The Builder instance. */ public @NonNull Builder cookieBehaviorPrivateMode(final @CBCookieBehavior int behavior) { getSettings().setCookieBehaviorPrivateMode(behavior); return this; } /** * Set the ETP behavior level. * * @param level The level of ETP blocking to use. Only takes effect if cookie behavior is set * to {@link ContentBlocking.CookieBehavior#ACCEPT_NON_TRACKERS} or {@link * ContentBlocking.CookieBehavior#ACCEPT_FIRST_PARTY_AND_ISOLATE_OTHERS}. * @return The Builder instance. */ public @NonNull Builder enhancedTrackingProtectionLevel(final @CBEtpLevel int level) { getSettings().setEnhancedTrackingProtectionLevel(level); return this; } /** * Set whether or not email tracker blocking is enabled in private mode. * * @param enabled A boolean indicating whether or not email tracker blocking should be enabled * in private mode. * @return The builder instance. */ public @NonNull Builder emailTrackerBlockingPrivateMode(final boolean enabled) { getSettings().setEmailTrackerBlockingPrivateBrowsing(enabled); return this; } /** * Set whether or not strict social tracking protection is enabled. This will block resources * from loading if they are on the social tracking protection list, rather than just blocking * cookies as with normal social tracking protection. * * @param enabled A boolean indicating whether or not strict social tracking protection should * be enabled. * @return The builder instance. */ public @NonNull Builder strictSocialTrackingProtection(final boolean enabled) { getSettings().setStrictSocialTrackingProtection(enabled); return this; } /** * Set whether or not to automatically purge tracking cookies. This will purge cookies from * tracking sites that do not have recent user interaction provided that the cookie behavior * is set to either {@link ContentBlocking.CookieBehavior#ACCEPT_NON_TRACKERS} or {@link * ContentBlocking.CookieBehavior#ACCEPT_FIRST_PARTY_AND_ISOLATE_OTHERS}. * * @param enabled A boolean indicating whether or not cookie purging should be enabled. * @return The builder instance. */ public @NonNull Builder cookiePurging(final boolean enabled) { getSettings().setCookiePurging(enabled); return this; } /** * Set the Cookie Banner Handling Mode. * * @param mode The mode of the Cookie Banner Handling one of the {@link CBCookieBannerMode}. * @return The Builder instance. */ public @NonNull Builder cookieBannerHandlingMode(final @CBCookieBannerMode int mode) { getSettings().setCookieBannerMode(mode); return this; } /** * When set to true, enable the use of global CookieBannerRules. * * @param enabled A boolean indicating whether to enable the use of global CookieBannerRules. * @return The Builder instance. */ public @NonNull Builder cookieBannerGlobalRulesEnabled(final boolean enabled) { getSettings().setCookieBannerGlobalRulesEnabled(enabled); return this; } /** * When set to true, enable the use of global CookieBannerRules in sub-frames. * * @param enabled A boolean indicating whether to enable the use of global CookieBannerRules * in sub-frames. * @return The Builder instance. */ public @NonNull Builder cookieBannerGlobalRulesSubFramesEnabled(final boolean enabled) { getSettings().setCookieBannerGlobalRulesSubFramesEnabled(enabled); return this; } /** * When set to true, query parameter stripping is enabled in normal mode. * * @param enabled A boolean indicating whether to query parameter stripping enabled in normal * mode. * @return The Builder instance. */ public @NonNull Builder queryParameterStrippingEnabled(final boolean enabled) { getSettings().setQueryParameterStrippingEnabled(enabled); return this; } /** * When set to true, query parameter stripping is enabled in private mode. * * @param enabled A boolean indicating whether to query parameter stripping enabled in private * mode. * @return The Builder instance. */ public @NonNull Builder queryParameterStrippingPrivateBrowsingEnabled(final boolean enabled) { getSettings().setQueryParameterStrippingPrivateBrowsingEnabled(enabled); return this; } /** * The allowed list for the query parameter stripping feature. * * @param list an array of identifiers for query parameter's stripping feature. * @return The Builder instance. */ public @NonNull Builder queryParameterStrippingAllowList(final @NonNull String... list) { getSettings().setQueryParameterStrippingAllowList(list); return this; } /** * The strip list for the query parameter stripping feature. * * @param list an array of identifiers for the strip list of the query parameter's stripping * feature. * @return The Builder instance. */ public @NonNull Builder queryParameterStrippingStripList(final @NonNull String... list) { getSettings().setQueryParameterStrippingStripList(list); return this; } /** * Set the Cookie Banner Handling Mode for private browsing. * * @param mode The mode of the Cookie Banner Handling one of the {@link CBCookieBannerMode}. * @return The Builder instance. */ public @NonNull Builder cookieBannerHandlingModePrivateBrowsing( final @CBCookieBannerMode int mode) { getSettings().setCookieBannerModePrivateBrowsing(mode); return this; } /** * When set to true, cookie banners are detected and detection events are dispatched, but they * will not be handled. * * @param enabled A boolean indicating whether to enable cookie banner detect only mode. * @return The Builder instance. */ public @NonNull Builder cookieBannerHandlingDetectOnlyMode(final boolean enabled) { getSettings().setCookieBannerDetectOnlyMode(enabled); return this; } } /* package */ final Pref mAt = new Pref( "urlclassifier.trackingTable", ContentBlocking.catToAtPref(AntiTracking.DEFAULT)); /* package */ final Pref mCm = new Pref("privacy.trackingprotection.cryptomining.enabled", false); /* package */ final Pref mCmList = new Pref( "urlclassifier.features.cryptomining.blacklistTables", ContentBlocking.catToCmListPref(AntiTracking.NONE)); /* package */ final Pref mFp = new Pref("privacy.trackingprotection.fingerprinting.enabled", false); /* package */ final Pref mFpList = new Pref( "urlclassifier.features.fingerprinting.blacklistTables", ContentBlocking.catToFpListPref(AntiTracking.NONE)); /* package */ final Pref mSt = new Pref("privacy.socialtracking.block_cookies.enabled", false); /* package */ final Pref mStStrict = new Pref("privacy.trackingprotection.socialtracking.enabled", false); /* package */ final Pref mStList = new Pref( "urlclassifier.features.socialtracking.annotate.blacklistTables", ContentBlocking.catToPref(AntiTracking.NONE, AntiTracking.STP, STP)); /* package */ final Pref mSbMalware = new Pref("browser.safebrowsing.malware.enabled", true); /* package */ final Pref mSbPhishing = new Pref("browser.safebrowsing.phishing.enabled", true); /* package */ final Pref mCookieBehavior = new Pref("network.cookie.cookieBehavior", CookieBehavior.ACCEPT_NON_TRACKERS); /* package */ final Pref mCookieBehaviorPrivateMode = new Pref( "network.cookie.cookieBehavior.pbmode", CookieBehavior.ACCEPT_NON_TRACKERS); /* package */ final Pref mCookiePurging = new Pref("privacy.purge_trackers.enabled", false); /* package */ final Pref mEtpEnabled = new Pref("privacy.trackingprotection.annotate_channels", false); /* package */ final Pref mEtpStrict = new Pref("privacy.annotate_channels.strict_list.enabled", false); /* package */ final Pref mCbhMode = new Pref( "cookiebanners.service.mode", CookieBannerMode.COOKIE_BANNER_MODE_DISABLED); /* package */ final Pref mCbhModePrivateBrowsing = new Pref( "cookiebanners.service.mode.privateBrowsing", CookieBannerMode.COOKIE_BANNER_MODE_REJECT); /* package */ final Pref mChbDetectOnlyMode = new Pref("cookiebanners.service.detectOnly", false); /* package */ final Pref mCbhGlobalRulesEnabled = new Pref("cookiebanners.service.enableGlobalRules", false); final Pref mCbhGlobalRulesSubFramesEnabled = new Pref("cookiebanners.service.enableGlobalRules.subFrames", false); /* package */ final Pref mQueryParameterStrippingEnabled = new Pref("privacy.query_stripping.enabled", false); /* package */ final Pref mQueryParameterStrippingPrivateBrowsingEnabled = new Pref("privacy.query_stripping.enabled.pbmode", false); /* package */ final Pref mQueryParameterStrippingAllowList = new Pref<>("privacy.query_stripping.allow_list", ""); /* package */ final Pref mQueryParameterStrippingStripList = new Pref<>("privacy.query_stripping.strip_list", ""); /* package */ final Pref mEtb = new Pref("privacy.trackingprotection.emailtracking.enabled", false); /* package */ final Pref mEtbPrivateBrowsing = new Pref("privacy.trackingprotection.emailtracking.pbmode.enabled", false); /* package */ final Pref mEtbList = new Pref( "urlclassifier.features.emailtracking.blocklistTables", ContentBlocking.catToPref(AntiTracking.NONE, AntiTracking.EMAIL, EMAIL)); /* package */ final Pref mSafeBrowsingMalwareTable = new Pref<>( "urlclassifier.malwareTable", ContentBlocking.listsToPref( "goog-malware-proto", "goog-unwanted-proto", "moztest-harmful-simple", "moztest-malware-simple", "moztest-unwanted-simple")); /* package */ final Pref mSafeBrowsingPhishingTable = new Pref<>( "urlclassifier.phishTable", ContentBlocking.listsToPref( // In official builds, we are allowed to use Google's private phishing // list (see bug 1288840). BuildConfig.MOZILLA_OFFICIAL ? "goog-phish-proto" : "googpub-phish-proto", "moztest-phish-simple")); /** Construct default settings. */ /* package */ Settings() { this(null /* settings */); } /** * Copy-construct settings. * * @param settings Copy from this settings. */ /* package */ Settings(final @Nullable Settings settings) { this(null /* parent */, settings); } /** * Copy-construct nested settings. * * @param parent The parent settings used for nesting. * @param settings Copy from this settings. */ /* package */ Settings( final @Nullable RuntimeSettings parent, final @Nullable Settings settings) { super(parent); if (settings != null) { updatePrefs(settings); } else { // Set default browsing providers setSafeBrowsingProviders(DEFAULT_PROVIDERS); } } @Override protected void updatePrefs(final @NonNull RuntimeSettings settings) { super.updatePrefs(settings); final ContentBlocking.Settings source = (ContentBlocking.Settings) settings; for (final SafeBrowsingProvider provider : source.mSafeBrowsingProviders.values()) { mSafeBrowsingProviders.put(provider.getName(), new SafeBrowsingProvider(this, provider)); } } /** * Get the collection of {@link SafeBrowsingProvider} for this runtime. * * @return an unmodifiable collection of {@link SafeBrowsingProvider} * @see SafeBrowsingProvider */ public @NonNull Collection getSafeBrowsingProviders() { return Collections.unmodifiableCollection(mSafeBrowsingProviders.values()); } /** * Sets the collection of {@link SafeBrowsingProvider} for this runtime. * *

By default the collection is composed of {@link * ContentBlocking#GOOGLE_LEGACY_SAFE_BROWSING_PROVIDER} and {@link * ContentBlocking#GOOGLE_SAFE_BROWSING_PROVIDER}. * * @param providers {@link SafeBrowsingProvider} instances for this runtime. * @return the {@link Settings} instance. * @see SafeBrowsingProvider */ public @NonNull Settings setSafeBrowsingProviders( final @NonNull SafeBrowsingProvider... providers) { mSafeBrowsingProviders.clear(); for (final SafeBrowsingProvider provider : providers) { mSafeBrowsingProviders.put(provider.getName(), new SafeBrowsingProvider(this, provider)); } return this; } /** * Get the table for SafeBrowsing Phishing. The identifiers present in this table must match one * of the identifiers present in {@link SafeBrowsingProvider#getLists}. * * @return an array of identifiers for SafeBrowsing's Phishing feature * @see SafeBrowsingProvider.Builder#lists */ public @NonNull String[] getSafeBrowsingPhishingTable() { return ContentBlocking.prefToLists(mSafeBrowsingPhishingTable.get()); } /** * Sets the table for SafeBrowsing Phishing. * * @param table an array of identifiers for SafeBrowsing's Phishing feature. * @return this {@link Settings} instance. * @see SafeBrowsingProvider.Builder#lists */ public @NonNull Settings setSafeBrowsingPhishingTable(final @NonNull String... table) { mSafeBrowsingPhishingTable.commit(ContentBlocking.listsToPref(table)); return this; } /** * Get the table for SafeBrowsing Malware. The identifiers present in this table must match one * of the identifiers present in {@link SafeBrowsingProvider#getLists}. * * @return an array of identifiers for SafeBrowsing's Malware feature * @see SafeBrowsingProvider.Builder#lists */ public @NonNull String[] getSafeBrowsingMalwareTable() { return ContentBlocking.prefToLists(mSafeBrowsingMalwareTable.get()); } /** * Sets the allowed list for the query parameter stripping feature. * * @param list an array of identifiers for the allowed list of the query parameter's stripping * feature. * @return this {@link Settings} instance. */ public @NonNull Settings setQueryParameterStrippingAllowList(final @NonNull String... list) { mQueryParameterStrippingAllowList.commit(ContentBlocking.listsToPref(list)); return this; } /** * Get the allowed list for the query parameter stripping feature. * * @return an array of identifiers for the allowed list for the query parameter stripping * feature. */ public @NonNull String[] getQueryParameterStrippingAllowList() { return ContentBlocking.prefToLists(mQueryParameterStrippingAllowList.get()); } /** * Sets the strip list for the query parameter stripping feature. * * @param list an array of identifiers for the strip list of the query parameter's stripping * feature. * @return this {@link Settings} instance. */ public @NonNull Settings setQueryParameterStrippingStripList(final @NonNull String... list) { mQueryParameterStrippingStripList.commit(ContentBlocking.listsToPref(list)); return this; } /** * Get the strip list for the query parameter stripping feature * * @return an array of identifiers for the allowed list for the query parameter stripping * feature. */ public @NonNull String[] getQueryParameterStrippingStripList() { return ContentBlocking.prefToLists(mQueryParameterStrippingStripList.get()); } /** * Sets the table for SafeBrowsing Malware. * * @param table an array of identifiers for SafeBrowsing's Malware feature. * @return this {@link Settings} instance. * @see SafeBrowsingProvider.Builder#lists */ public @NonNull Settings setSafeBrowsingMalwareTable(final @NonNull String... table) { mSafeBrowsingMalwareTable.commit(ContentBlocking.listsToPref(table)); return this; } /** * Set anti-tracking categories. * * @param cat The categories of resources that should be blocked. Use one or more of the {@link * ContentBlocking.AntiTracking} flags. * @return This Settings instance. */ public @NonNull Settings setAntiTracking(final @CBAntiTracking int cat) { mAt.commit(ContentBlocking.catToAtPref(cat)); mCm.commit(ContentBlocking.catToCmPref(cat)); mCmList.commit(ContentBlocking.catToCmListPref(cat)); mFp.commit(ContentBlocking.catToFpPref(cat)); mFpList.commit(ContentBlocking.catToFpListPref(cat)); mSt.commit(ContentBlocking.catToStPref(cat)); mStList.commit(ContentBlocking.catToPref(cat, AntiTracking.STP, STP)); mEtb.commit(ContentBlocking.catToEtbPref(cat)); mEtbList.commit(ContentBlocking.catToPref(cat, AntiTracking.EMAIL, EMAIL)); return this; } /** * Set the ETP behavior level. * * @param level The level of ETP blocking to use; must be one of {@link * ContentBlocking.EtpLevel} flags. Only takes effect if the cookie behavior is {@link * ContentBlocking.CookieBehavior#ACCEPT_NON_TRACKERS} or {@link * ContentBlocking.CookieBehavior#ACCEPT_FIRST_PARTY_AND_ISOLATE_OTHERS}. * @return This Settings instance. */ public @NonNull Settings setEnhancedTrackingProtectionLevel(final @CBEtpLevel int level) { mEtpEnabled.commit( level == ContentBlocking.EtpLevel.DEFAULT || level == ContentBlocking.EtpLevel.STRICT); mEtpStrict.commit(level == ContentBlocking.EtpLevel.STRICT); return this; } /** * Set whether or not strict social tracking protection is enabled (ie, whether to block content * or just cookies). Will only block if social tracking protection lists are supplied to {@link * #setAntiTracking}. * * @param enabled A boolean indicating whether or not to enable strict social tracking * protection. * @return This Settings instance. */ public @NonNull Settings setStrictSocialTrackingProtection(final boolean enabled) { mStStrict.commit(enabled); return this; } /** * Set safe browsing categories. * * @param cat The categories of resources that should be blocked. Use one or more of the {@link * ContentBlocking.SafeBrowsing} flags. * @return This Settings instance. */ public @NonNull Settings setSafeBrowsing(final @CBSafeBrowsing int cat) { mSbMalware.commit(ContentBlocking.catToSbMalware(cat)); mSbPhishing.commit(ContentBlocking.catToSbPhishing(cat)); return this; } /** * Get the set anti-tracking categories. * * @return The categories of resources to be blocked. */ public @CBAntiTracking int getAntiTrackingCategories() { return ContentBlocking.atListToAtCat(mAt.get()) | ContentBlocking.cmListToAtCat(mCmList.get()) | ContentBlocking.fpListToAtCat(mFpList.get()) | ContentBlocking.stListToAtCat(mStList.get()) | ContentBlocking.etbListToAtCat(mEtbList.get()); } /** * Get the set ETP behavior level. * * @return The current ETP level; one of {@link ContentBlocking.EtpLevel}. */ public @CBEtpLevel int getEnhancedTrackingProtectionLevel() { if (mEtpStrict.get()) { return ContentBlocking.EtpLevel.STRICT; } else if (mEtpEnabled.get()) { return ContentBlocking.EtpLevel.DEFAULT; } return ContentBlocking.EtpLevel.NONE; } /** * Get whether or not strict social tracking protection is enabled. * * @return A boolean indicating whether or not strict social tracking protection is enabled. */ public boolean getStrictSocialTrackingProtection() { return mStStrict.get(); } /** * Get the set safe browsing categories. * * @return The categories of resources to be blocked. */ public @CBSafeBrowsing int getSafeBrowsingCategories() { return ContentBlocking.sbMalwareToSbCat(mSbMalware.get()) | ContentBlocking.sbPhishingToSbCat(mSbPhishing.get()); } /** * Get the assigned cookie storage behavior. * * @return The assigned behavior, as one of {@link CookieBehavior} flags. */ @SuppressLint("WrongConstant") public @CBCookieBehavior int getCookieBehavior() { return mCookieBehavior.get(); } /** * Set cookie storage behavior. * * @param behavior The storage behavior that should be applied. Use one of the {@link * CookieBehavior} flags. * @return This Settings instance. */ public @NonNull Settings setCookieBehavior(final @CBCookieBehavior int behavior) { mCookieBehavior.commit(behavior); return this; } /** * Get the assigned private mode cookie storage behavior. * * @return The assigned behavior, as one of {@link CookieBehavior} flags. */ @SuppressLint("WrongConstant") public @CBCookieBehavior int getCookieBehaviorPrivateMode() { return mCookieBehaviorPrivateMode.get(); } /** * Set cookie storage behavior for private browsing mode. * * @param behavior The storage behavior that should be applied. Use one of the {@link * CookieBehavior} flags. * @return This Settings instance. */ public @NonNull Settings setCookieBehaviorPrivateMode(final @CBCookieBehavior int behavior) { mCookieBehaviorPrivateMode.commit(behavior); return this; } /** * Get whether or not cookie purging is enabled. * * @return A boolean indicating whether or not cookie purging is enabled. */ public boolean getCookiePurging() { return mCookiePurging.get(); } /** * Enable or disable cookie purging. This will automatically purge cookies from tracking sites * that have no recent user interaction, provided the cookie behavior is set to {@link * ContentBlocking.CookieBehavior#ACCEPT_NON_TRACKERS} or {@link * ContentBlocking.CookieBehavior#ACCEPT_FIRST_PARTY_AND_ISOLATE_OTHERS}. * * @param enabled A boolean indicating whether to enable cookie purging. * @return This Settings instance. */ public @NonNull Settings setCookiePurging(final boolean enabled) { mCookiePurging.commit(enabled); return this; } /** * Set the Cookie Banner Handling Mode to the new provided {@link CBCookieBannerMode} value. * * @param mode Integer indicating the new mode. * @return This Settings instance. */ public @NonNull Settings setCookieBannerMode(final @CBCookieBannerMode int mode) { mCbhMode.commit(mode); return this; } /** * When set to true, cookie banners are detected and detection events are dispatched, but they * will not be handled. Requires the service to be enabled for the desired mode via * setCookieBannerMode. * * @param enabled A boolean indicating whether to enable cookie banners. * @return This Settings instance. */ public @NonNull Settings setCookieBannerDetectOnlyMode(final boolean enabled) { mChbDetectOnlyMode.commit(enabled); return this; } /** * Enables/disables the use of global CookieBannerRules, which apply to all sites. This enable * handling of CMPs across sites without the use of site-specific rules. * * @param enabled A boolean indicating whether or not to enable. * @return This Settings instance. */ public @NonNull Settings setCookieBannerGlobalRulesEnabled(final boolean enabled) { mCbhGlobalRulesEnabled.commit(enabled); return this; } /** * Indicates if global CookieBannerRules is enabled or not. * * @return Indicates if global CookieBannerRule is enabled or disabled. */ public boolean getCookieBannerGlobalRulesEnabled() { return mCbhGlobalRulesEnabled.get(); } /** * Whether global rules are allowed to run in sub-frames. Running query selectors in every * sub-frame may negatively impact performance, but is required for some CMPs. * * @param enabled A boolean indicating whether or not to enable. * @return This Settings instance. */ public @NonNull Settings setCookieBannerGlobalRulesSubFramesEnabled(final boolean enabled) { mCbhGlobalRulesSubFramesEnabled.commit(enabled); return this; } /** * Indicates if email tracker blocking is enabled in private mode. * * @return Indicates if email tracker blocking is enabled or disabled in private mode. */ public @NonNull Boolean getEmailTrackerBlockingPrivateBrowsingEnabled() { return mEtbPrivateBrowsing.get(); } /** * Sets whether email tracker blocking is enabled in private mode. * * @param enabled A boolean indicating whether or not to enable. * @return This Settings instance. */ public @NonNull Settings setEmailTrackerBlockingPrivateBrowsing(final boolean enabled) { mEtbPrivateBrowsing.commit(enabled); return this; } /** * Sets whether query parameter stripping is enabled in normal mode. * * @param enabled A boolean indicating whether or not to enable. * @return This Settings instance. */ public @NonNull Settings setQueryParameterStrippingEnabled(final boolean enabled) { mQueryParameterStrippingEnabled.commit(enabled); return this; } /** * Indicates if query parameter stripping is enabled in normal mode. * * @return Indicates if query parameter stripping is enabled or disabled in normal mode. */ public boolean getQueryParameterStrippingEnabled() { return mQueryParameterStrippingEnabled.get(); } /** * Sets Whether query parameter stripping is enabled in private mode. * * @param enabled A boolean indicating whether or not to enable in private mode. * @return This Settings instance. */ public @NonNull Settings setQueryParameterStrippingPrivateBrowsingEnabled( final boolean enabled) { mQueryParameterStrippingPrivateBrowsingEnabled.commit(enabled); return this; } /** * Indicates if query parameter stripping is enabled in private mode. * * @return Indicates if global CookieBannerRules is enabled or disabled in sub-frames. */ public boolean getQueryParameterStrippingPrivateBrowsingEnabled() { return mQueryParameterStrippingPrivateBrowsingEnabled.get(); } /** * Indicates if global CookieBannerRules is enabled or not in sub-frames. * * @return Indicates if global CookieBannerRules is enabled or disabled in sub-frames. */ public boolean getCookieBannerGlobalRulesSubFramesEnabled() { return mCbhGlobalRulesSubFramesEnabled.get(); } /** * Indicates if cookie banner handling detect only mode is enabled. * * @return boolean indicating if the cookie banner handling detect only mode setting is enabled. */ public boolean getCookieBannerDetectOnlyMode() { return mChbDetectOnlyMode.get(); } /** * Gets the current cookie banner handling mode. * * @return int the current cookie banner handling mode, one of the {@link CBCookieBannerMode}. */ @SuppressLint("WrongConstant") public @CBCookieBannerMode int getCookieBannerMode() { return mCbhMode.get(); } /** * Set the Cookie Banner Handling Mode for private browsing to the new provided {@link * CBCookieBannerMode} value. * * @param mode Integer indicating the new mode. * @return This Settings instance. */ public @NonNull Settings setCookieBannerModePrivateBrowsing( final @CBCookieBannerMode int mode) { mCbhModePrivateBrowsing.commit(mode); return this; } /** * Gets the current cookie banner handling mode for private browsing. * * @return int the current cookie banner handling mode, one of the {@link CBCookieBannerMode}. */ @SuppressLint("WrongConstant") public @CBCookieBannerMode int getCookieBannerModePrivateBrowsing() { return mCbhModePrivateBrowsing.get(); } public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { @Override public Settings createFromParcel(final Parcel in) { final Settings settings = new Settings(); settings.readFromParcel(in); return settings; } @Override public Settings[] newArray(final int size) { return new Settings[size]; } }; } /** * Holds configuration for a SafeBrowsing provider.
*
* This class can be used to modify existing configuration for SafeBrowsing providers or to add a * custom SafeBrowsing provider to the app.
*
* Default configuration for Google's SafeBrowsing servers can be found at {@link * ContentBlocking#GOOGLE_SAFE_BROWSING_PROVIDER} and {@link * ContentBlocking#GOOGLE_LEGACY_SAFE_BROWSING_PROVIDER}.
*
* This class is immutable, once constructed its values cannot be changed.
*
* You can, however, use the {@link #from} method to build upon an existing configuration. For * example to override the Google's server configuration, you can do the following:
* *


   *     SafeBrowsingProvider override = SafeBrowsingProvider
   *         .from(ContentBlocking.GOOGLE_SAFE_BROWSING_PROVIDER)
   *         .getHashUrl("http://my-custom-server.com/...")
   *         .updateUrl("http://my-custom-server.com/...")
   *         .build();
   *
   *     runtime.getContentBlocking().setSafeBrowsingProviders(override);
   * 
* * This will override the configuration.
*
* You can also add a custom SafeBrowsing provider using the {@link #withName} method. For * example, to add a custom provider that provides the list testprovider-phish-digest256 * do the following:
* *

   *     SafeBrowsingProvider custom = SafeBrowsingProvider
   *         .withName("custom-provider")
   *         .version("2.2")
   *         .lists("testprovider-phish-digest256")
   *         .updateUrl("http://my-custom-server2.com/...")
   *         .getHashUrl("http://my-custom-server2.com/...")
   *         .build();
   * 
* * And then add the custom provider (adding optionally existing providers):
* *

   *     runtime.getContentBlocking().setSafeBrowsingProviders(
   *         custom,
   *         // Add this if you want to keep the existing configuration too.
   *         ContentBlocking.GOOGLE_SAFE_BROWSING_PROVIDER,
   *         ContentBlocking.GOOGLE_LEGACY_SAFE_BROWSING_PROVIDER);
   * 
* * And set the list in the phishing configuration
* *

   *     runtime.getContentBlocking().setSafeBrowsingPhishingTable(
   *          "testprovider-phish-digest256",
   *          // Existing configuration
   *          "goog-phish-proto");
   * 
* * Note that any list present in the phishing or malware tables need to appear in one safe * browsing provider's {@link #getLists} property. * *

See also safe-browsing/v4. */ @AnyThread public static class SafeBrowsingProvider extends RuntimeSettings { private static final String ROOT = "browser.safebrowsing.provider."; private final String mName; /* package */ final Pref mVersion; /* package */ final Pref mLists; /* package */ final Pref mUpdateUrl; /* package */ final Pref mGetHashUrl; /* package */ final Pref mReportUrl; /* package */ final Pref mReportPhishingMistakeUrl; /* package */ final Pref mReportMalwareMistakeUrl; /* package */ final Pref mAdvisoryUrl; /* package */ final Pref mAdvisoryName; /* package */ final Pref mDataSharingUrl; /* package */ final Pref mDataSharingEnabled; /** * Creates a {@link SafeBrowsingProvider.Builder} for a provider with the given name. * *

Note: the mozilla name is reserved for internal use, and this method will * throw if you attempt to build a provider with that name. * * @param name The name of the provider. * @return a {@link Builder} instance that can be used to build a provider. * @throws IllegalArgumentException if this method is called with name="mozilla" */ @NonNull public static Builder withName(final @NonNull String name) { if ("mozilla".equals(name)) { throw new IllegalArgumentException("The 'mozilla' name is reserved for internal use."); } return new Builder(name); } /** * Creates a {@link SafeBrowsingProvider.Builder} based on the given provider. * *

All properties not otherwise specified will be copied from the provider given in input. * * @param provider The source provider for this builder. * @return a {@link Builder} instance that can be used to create a configuration based on the * builder in input. */ @NonNull public static Builder from(final @NonNull SafeBrowsingProvider provider) { return new Builder(provider); } @AnyThread public static class Builder { final SafeBrowsingProvider mProvider; private Builder(final String name) { mProvider = new SafeBrowsingProvider(name); } private Builder(final SafeBrowsingProvider source) { mProvider = new SafeBrowsingProvider(source); } /** * Sets the SafeBrowsing protocol session for this provider. * * @param version the version strong, e.g. "2.2" or "4". * @return this {@link Builder} instance. */ public @NonNull Builder version(final @NonNull String version) { mProvider.mVersion.set(version); return this; } /** * Sets the lists provided by this provider. * * @param lists one or more lists for this provider, e.g. "goog-malware-proto", * "goog-unwanted-proto" * @return this {@link Builder} instance. */ public @NonNull Builder lists(final @NonNull String... lists) { mProvider.mLists.set(ContentBlocking.listsToPref(lists)); return this; } /** * Sets the url that will be used to update the threat list for this provider. * *

See also * v4/threadListUpdates/fetch . * * @param updateUrl the update url endpoint for this provider * @return this {@link Builder} instance. */ public @NonNull Builder updateUrl(final @NonNull String updateUrl) { mProvider.mUpdateUrl.set(updateUrl); return this; } /** * Sets the url that will be used to get the full hashes that match a partial hash. * *

See also * v4/fullHashes/find . * * @param getHashUrl the gethash url endpoint for this provider * @return this {@link Builder} instance. */ public @NonNull Builder getHashUrl(final @NonNull String getHashUrl) { mProvider.mGetHashUrl.set(getHashUrl); return this; } /** * Set the url that will be used to report a url to the SafeBrowsing provider. * * @param reportUrl the url endpoint to report a url to this provider. * @return this {@link Builder} instance. */ public @NonNull Builder reportUrl(final @NonNull String reportUrl) { mProvider.mReportUrl.set(reportUrl); return this; } /** * Set the url that will be used to report a url mistakenly reported as Phishing to the * SafeBrowsing provider. * * @param reportPhishingMistakeUrl the url endpoint to report a url to this provider. * @return this {@link Builder} instance. */ public @NonNull Builder reportPhishingMistakeUrl( final @NonNull String reportPhishingMistakeUrl) { mProvider.mReportPhishingMistakeUrl.set(reportPhishingMistakeUrl); return this; } /** * Set the url that will be used to report a url mistakenly reported as Malware to the * SafeBrowsing provider. * * @param reportMalwareMistakeUrl the url endpoint to report a url to this provider. * @return this {@link Builder} instance. */ public @NonNull Builder reportMalwareMistakeUrl( final @NonNull String reportMalwareMistakeUrl) { mProvider.mReportMalwareMistakeUrl.set(reportMalwareMistakeUrl); return this; } /** * Set the url that will be used to give a general advisory about this SafeBrowsing provider. * * @param advisoryUrl the adivisory page url for this provider. * @return this {@link Builder} instance. */ public @NonNull Builder advisoryUrl(final @NonNull String advisoryUrl) { mProvider.mAdvisoryUrl.set(advisoryUrl); return this; } /** * Set the advisory name for this provider. * * @param advisoryName the adivisory name for this provider. * @return this {@link Builder} instance. */ public @NonNull Builder advisoryName(final @NonNull String advisoryName) { mProvider.mAdvisoryName.set(advisoryName); return this; } /** * Set url to share threat data to the provider, if enabled by {@link #dataSharingEnabled}. * * @param dataSharingUrl the url endpoint * @return this {@link Builder} instance. */ public @NonNull Builder dataSharingUrl(final @NonNull String dataSharingUrl) { mProvider.mDataSharingUrl.set(dataSharingUrl); return this; } /** * Set whether to share threat data with the provider, off by default. * * @param dataSharingEnabled true if the browser should share threat data with * the provider. * @return this {@link Builder} instance. */ public @NonNull Builder dataSharingEnabled(final boolean dataSharingEnabled) { mProvider.mDataSharingEnabled.set(dataSharingEnabled); return this; } /** * Build the {@link SafeBrowsingProvider} based on this {@link Builder} instance. * * @return thie {@link SafeBrowsingProvider} instance. */ public @NonNull SafeBrowsingProvider build() { return new SafeBrowsingProvider(mProvider); } } /* package */ SafeBrowsingProvider(final SafeBrowsingProvider source) { this(/* name */ null, /* parent */ null, source); } /* package */ SafeBrowsingProvider( final RuntimeSettings parent, final SafeBrowsingProvider source) { this(/* name */ null, parent, source); } /* package */ SafeBrowsingProvider(final String name) { this(name, /* parent */ null, /* source */ null); } /* package */ SafeBrowsingProvider( final String name, final RuntimeSettings parent, final SafeBrowsingProvider source) { super(parent); if (name != null) { mName = name; } else if (source != null) { mName = source.mName; } else { throw new IllegalArgumentException("Either name or source must be non-null"); } mVersion = new Pref<>(ROOT + mName + ".pver", null); mLists = new Pref<>(ROOT + mName + ".lists", null); mUpdateUrl = new Pref<>(ROOT + mName + ".updateURL", null); mGetHashUrl = new Pref<>(ROOT + mName + ".gethashURL", null); mReportUrl = new Pref<>(ROOT + mName + ".reportURL", null); mReportPhishingMistakeUrl = new Pref<>(ROOT + mName + ".reportPhishMistakeURL", null); mReportMalwareMistakeUrl = new Pref<>(ROOT + mName + ".reportMalwareMistakeURL", null); mAdvisoryUrl = new Pref<>(ROOT + mName + ".advisoryURL", null); mAdvisoryName = new Pref<>(ROOT + mName + ".advisoryName", null); mDataSharingUrl = new Pref<>(ROOT + mName + ".dataSharingURL", null); mDataSharingEnabled = new Pref<>(ROOT + mName + ".dataSharing.enabled", false); if (source != null) { updatePrefs(source); } } /** * Get the name of this provider. * * @return a string containing the name. */ public @NonNull String getName() { return mName; } /** * Get the version for this provider. * * @return a string representing the version, e.g. "2.2" or "4". */ public @Nullable String getVersion() { return mVersion.get(); } /** * Get the lists provided by this provider. * * @return an array of string identifiers for the lists */ public @NonNull String[] getLists() { return ContentBlocking.prefToLists(mLists.get()); } /** * Get the url that will be used to update the threat list for this provider. * *

See also * v4/threadListUpdates/fetch . * * @return a string containing the URL. */ public @Nullable String getUpdateUrl() { return mUpdateUrl.get(); } /** * Get the url that will be used to get the full hashes that match a partial hash. * *

See also * v4/fullHashes/find . * * @return a string containing the URL. */ public @Nullable String getGetHashUrl() { return mGetHashUrl.get(); } /** * Get the url that will be used to report a url to the SafeBrowsing provider. * * @return a string containing the URL. */ public @Nullable String getReportUrl() { return mReportUrl.get(); } /** * Get the url that will be used to report a url mistakenly reported as Phishing to the * SafeBrowsing provider. * * @return a string containing the URL. */ public @Nullable String getReportPhishingMistakeUrl() { return mReportPhishingMistakeUrl.get(); } /** * Get the url that will be used to report a url mistakenly reported as Malware to the * SafeBrowsing provider. * * @return a string containing the URL. */ public @Nullable String getReportMalwareMistakeUrl() { return mReportMalwareMistakeUrl.get(); } /** * Get the url that will be used to give a general advisory about this SafeBrowsing provider. * * @return a string containing the URL. */ public @Nullable String getAdvisoryUrl() { return mAdvisoryUrl.get(); } /** * Get the advisory name for this provider. * * @return a string containing the URL. */ public @Nullable String getAdvisoryName() { return mAdvisoryName.get(); } /** * Get the url to share threat data to the provider, if enabled by {@link * #getDataSharingEnabled}. * * @return this {@link Builder} instance. */ public @Nullable String getDataSharingUrl() { return mDataSharingUrl.get(); } /** * Get whether to share threat data with the provider. * * @return true if the browser should whare threat data with the provider, * false otherwise. */ public @Nullable Boolean getDataSharingEnabled() { return mDataSharingEnabled.get(); } @Override // Parcelable @AnyThread public void writeToParcel(final Parcel out, final int flags) { out.writeValue(mName); super.writeToParcel(out, flags); } /** Creator instance for this class. */ public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { @Override public SafeBrowsingProvider createFromParcel(final Parcel source) { final String name = (String) source.readValue(getClass().getClassLoader()); final SafeBrowsingProvider settings = new SafeBrowsingProvider(name); settings.readFromParcel(source); return settings; } @Override public SafeBrowsingProvider[] newArray(final int size) { return new SafeBrowsingProvider[size]; } }; } private static String listsToPref(final String... lists) { final StringBuilder prefBuilder = new StringBuilder(); for (final String list : lists) { if (list.contains(",")) { // We use ',' as the separator, so the list name cannot contain it. // Should never happen. throw new IllegalArgumentException("List name cannot contain ',' character."); } prefBuilder.append(list); prefBuilder.append(","); } // Remove trailing "," if (lists.length > 0) { prefBuilder.setLength(prefBuilder.length() - 1); } return prefBuilder.toString(); } private static String[] prefToLists(final String pref) { return pref != null ? pref.split(",") : new String[] {}; } public static class AntiTracking { public static final int NONE = 0; /** Block advertisement trackers. */ public static final int AD = 1 << 1; /** Block analytics trackers. */ public static final int ANALYTIC = 1 << 2; /** * Block social trackers. Note: This is not the same as "Social Tracking Protection", which is * controlled by {@link #STP}. */ public static final int SOCIAL = 1 << 3; /** Block content trackers. May cause issues with some web sites. */ public static final int CONTENT = 1 << 4; /** Block Gecko test trackers (used for tests). */ public static final int TEST = 1 << 5; /** Block cryptocurrency miners. */ public static final int CRYPTOMINING = 1 << 6; /** Block fingerprinting trackers. */ public static final int FINGERPRINTING = 1 << 7; /** Block trackers on the Social Tracking Protection list. */ public static final int STP = 1 << 8; /** Block email trackers */ public static final int EMAIL = 1 << 9; /** Block ad, analytic, social and test trackers. */ public static final int DEFAULT = AD | ANALYTIC | SOCIAL | TEST; /** Block all known trackers. May cause issues with some web sites. */ public static final int STRICT = DEFAULT | CONTENT | CRYPTOMINING | FINGERPRINTING | EMAIL; protected AntiTracking() {} } @Retention(RetentionPolicy.SOURCE) @IntDef( flag = true, value = { AntiTracking.AD, AntiTracking.ANALYTIC, AntiTracking.SOCIAL, AntiTracking.CONTENT, AntiTracking.TEST, AntiTracking.CRYPTOMINING, AntiTracking.FINGERPRINTING, AntiTracking.DEFAULT, AntiTracking.STRICT, AntiTracking.STP, AntiTracking.EMAIL, AntiTracking.NONE }) public @interface CBAntiTracking {} public static class SafeBrowsing { public static final int NONE = 0; /** Block malware sites. */ public static final int MALWARE = 1 << 10; /** Block unwanted sites. */ public static final int UNWANTED = 1 << 11; /** Block harmful sites. */ public static final int HARMFUL = 1 << 12; /** Block phishing sites. */ public static final int PHISHING = 1 << 13; /** Block all unsafe sites. */ public static final int DEFAULT = MALWARE | UNWANTED | HARMFUL | PHISHING; protected SafeBrowsing() {} } @Retention(RetentionPolicy.SOURCE) @IntDef( flag = true, value = { SafeBrowsing.MALWARE, SafeBrowsing.UNWANTED, SafeBrowsing.HARMFUL, SafeBrowsing.PHISHING, SafeBrowsing.DEFAULT, SafeBrowsing.NONE }) public @interface CBSafeBrowsing {} // Sync values with nsICookieService.idl. public static class CookieBehavior { /** Accept first-party and third-party cookies and site data. */ public static final int ACCEPT_ALL = 0; /** * Accept only first-party cookies and site data to block cookies which are not associated with * the domain of the visited site. */ public static final int ACCEPT_FIRST_PARTY = 1; /** Do not store any cookies and site data. */ public static final int ACCEPT_NONE = 2; /** * Accept first-party and third-party cookies and site data only from sites previously visited * in a first-party context. */ public static final int ACCEPT_VISITED = 3; /** * Accept only first-party and non-tracking third-party cookies and site data to block cookies * which are not associated with the domain of the visited site set by known trackers. */ public static final int ACCEPT_NON_TRACKERS = 4; /** * Enable dynamic first party isolation (dFPI); this will block third-party tracking cookies in * accordance with the ETP level and isolate non-tracking third-party cookies. */ public static final int ACCEPT_FIRST_PARTY_AND_ISOLATE_OTHERS = 5; protected CookieBehavior() {} } @Retention(RetentionPolicy.SOURCE) @IntDef({ CookieBehavior.ACCEPT_ALL, CookieBehavior.ACCEPT_FIRST_PARTY, CookieBehavior.ACCEPT_NONE, CookieBehavior.ACCEPT_VISITED, CookieBehavior.ACCEPT_NON_TRACKERS }) public @interface CBCookieBehavior {} @Retention(RetentionPolicy.SOURCE) @IntDef({EtpLevel.NONE, EtpLevel.DEFAULT, EtpLevel.STRICT}) public @interface CBEtpLevel {} /** Possible settings for ETP. */ public static class EtpLevel { /** Do not enable ETP at all. */ public static final int NONE = 0; /** Enable ETP for ads, analytic, and social tracking lists. */ public static final int DEFAULT = 1; /** * Enable ETP for all of the default lists as well as the content list. May break many sites! */ public static final int STRICT = 2; } /** Holds content block event details. */ public static class BlockEvent { /** The URI of the blocked resource. */ public final @NonNull String uri; private final @CBAntiTracking int mAntiTrackingCat; private final @CBSafeBrowsing int mSafeBrowsingCat; private final @CBCookieBehavior int mCookieBehaviorCat; private final boolean mIsBlocking; @SuppressWarnings("checkstyle:javadocmethod") public BlockEvent( @NonNull final String uri, final @CBAntiTracking int atCat, final @CBSafeBrowsing int sbCat, final @CBCookieBehavior int cbCat, final boolean isBlocking) { this.uri = uri; this.mAntiTrackingCat = atCat; this.mSafeBrowsingCat = sbCat; this.mCookieBehaviorCat = cbCat; this.mIsBlocking = isBlocking; } /** * The anti-tracking category types of the blocked resource. * * @return One or more of the {@link AntiTracking} flags. */ @UiThread public @CBAntiTracking int getAntiTrackingCategory() { return mAntiTrackingCat; } /** * The safe browsing category types of the blocked resource. * * @return One or more of the {@link SafeBrowsing} flags. */ @UiThread public @CBSafeBrowsing int getSafeBrowsingCategory() { return mSafeBrowsingCat; } /** * The cookie types of the blocked resource. * * @return One or more of the {@link CookieBehavior} flags. */ @UiThread public @CBCookieBehavior int getCookieBehaviorCategory() { return mCookieBehaviorCat; } /* package */ static BlockEvent fromBundle(@NonNull final GeckoBundle bundle) { final String uri = bundle.getString("uri"); final String blockedList = bundle.getString("blockedList"); final String loadedList = TextUtils.join(",", bundle.getStringArray("loadedLists")); final long error = bundle.getLong("error", 0L); final long category = bundle.getLong("category", 0L); final String matchedList = blockedList != null ? blockedList : loadedList; // Note: Even if loadedList is non-empty it does not necessarily // mean that the event is not a blocking event. final boolean blocking = (blockedList != null || error != 0L || ContentBlocking.isBlockingGeckoCbCat(category)); return new BlockEvent( uri, ContentBlocking.atListToAtCat(matchedList) | ContentBlocking.cmListToAtCat(matchedList) | ContentBlocking.fpListToAtCat(matchedList) | ContentBlocking.stListToAtCat(matchedList) | ContentBlocking.etbListToAtCat(matchedList), ContentBlocking.errorToSbCat(error), ContentBlocking.geckoCatToCbCat(category), blocking); } @UiThread @SuppressWarnings("checkstyle:javadocmethod") public boolean isBlocking() { return mIsBlocking; } } /** GeckoSession applications implement this interface to handle content blocking events. */ public interface Delegate { /** * A content element has been blocked from loading. Set blocked element categories via {@link * GeckoRuntimeSettings} and enable content blocking via {@link GeckoSessionSettings}. * * @param session The GeckoSession that initiated the callback. * @param event The {@link BlockEvent} details. */ @UiThread default void onContentBlocked( @NonNull final GeckoSession session, @NonNull final BlockEvent event) {} /** * A content element that could be blocked has been loaded. * * @param session The GeckoSession that initiated the callback. * @param event The {@link BlockEvent} details. */ @UiThread default void onContentLoaded( @NonNull final GeckoSession session, @NonNull final BlockEvent event) {} } private static final String TEST = "moztest-track-simple"; private static final String AD = "ads-track-digest256"; private static final String ANALYTIC = "analytics-track-digest256"; private static final String SOCIAL = "social-track-digest256"; private static final String CONTENT = "content-track-digest256"; private static final String CRYPTOMINING = "base-cryptomining-track-digest256"; private static final String FINGERPRINTING = "base-fingerprinting-track-digest256"; private static final String STP = "social-tracking-protection-facebook-digest256,social-tracking-protection-linkedin-digest256,social-tracking-protection-twitter-digest256"; private static final String EMAIL = "base-email-track-digest256"; /* package */ static @CBSafeBrowsing int sbMalwareToSbCat(final boolean enabled) { return enabled ? (SafeBrowsing.MALWARE | SafeBrowsing.UNWANTED | SafeBrowsing.HARMFUL) : SafeBrowsing.NONE; } /* package */ static @CBSafeBrowsing int sbPhishingToSbCat(final boolean enabled) { return enabled ? SafeBrowsing.PHISHING : SafeBrowsing.NONE; } /* package */ static boolean catToSbMalware(@CBAntiTracking final int cat) { return (cat & (SafeBrowsing.MALWARE | SafeBrowsing.UNWANTED | SafeBrowsing.HARMFUL)) != 0; } /* package */ static boolean catToSbPhishing(@CBAntiTracking final int cat) { return (cat & SafeBrowsing.PHISHING) != 0; } /* package */ static String catToAtPref(@CBAntiTracking final int cat) { final StringBuilder builder = new StringBuilder(); if ((cat & AntiTracking.TEST) != 0) { builder.append(TEST).append(','); } if ((cat & AntiTracking.AD) != 0) { builder.append(AD).append(','); } if ((cat & AntiTracking.ANALYTIC) != 0) { builder.append(ANALYTIC).append(','); } if ((cat & AntiTracking.SOCIAL) != 0) { builder.append(SOCIAL).append(','); } if ((cat & AntiTracking.CONTENT) != 0) { builder.append(CONTENT).append(','); } if (builder.length() == 0) { return ""; } // Trim final ','. return builder.substring(0, builder.length() - 1); } /* package */ static boolean catToCmPref(@CBAntiTracking final int cat) { return (cat & AntiTracking.CRYPTOMINING) != 0; } /* package */ static String catToCmListPref(@CBAntiTracking final int cat) { final StringBuilder builder = new StringBuilder(); if ((cat & AntiTracking.CRYPTOMINING) != 0) { builder.append(CRYPTOMINING); } return builder.toString(); } /* package */ static boolean catToFpPref(@CBAntiTracking final int cat) { return (cat & AntiTracking.FINGERPRINTING) != 0; } /* package */ static String catToFpListPref(@CBAntiTracking final int cat) { final StringBuilder builder = new StringBuilder(); if ((cat & AntiTracking.FINGERPRINTING) != 0) { builder.append(FINGERPRINTING); } return builder.toString(); } /* package */ static @CBAntiTracking int fpListToAtCat(final String list) { int cat = AntiTracking.NONE; if (list == null) { return cat; } if (list.indexOf(FINGERPRINTING) != -1) { cat |= AntiTracking.FINGERPRINTING; } return cat; } /* package */ static boolean catToStPref(@CBAntiTracking final int cat) { return (cat & AntiTracking.STP) != 0; } /* package */ static boolean catToEtbPref(@CBAntiTracking final int cat) { return (cat & AntiTracking.EMAIL) != 0; } /** * Generic method for converting a category of anti-tracking to a Pref. * * @param cat Int representing the enabled anti-tracking blockers. * @param tbCat Int representing the category mask to check for. * @param catPrefString String to return if [cat] contains [tbCat]. * @return Pref string if [cat] contains [tbCat] otherwise empty string. */ /* package */ static String catToPref( @CBAntiTracking final int cat, final int tbCat, final String catPrefString) { if ((cat & tbCat) != 0) { return catPrefString; } else { return ""; } } /* package */ static @CBAntiTracking int atListToAtCat(final String list) { int cat = AntiTracking.NONE; if (list == null) { return cat; } if (list.indexOf(TEST) != -1) { cat |= AntiTracking.TEST; } if (list.indexOf(AD) != -1) { cat |= AntiTracking.AD; } if (list.indexOf(ANALYTIC) != -1) { cat |= AntiTracking.ANALYTIC; } if (list.indexOf(SOCIAL) != -1) { cat |= AntiTracking.SOCIAL; } if (list.indexOf(CONTENT) != -1) { cat |= AntiTracking.CONTENT; } return cat; } /* package */ static @CBAntiTracking int cmListToAtCat(final String list) { int cat = AntiTracking.NONE; if (list == null) { return cat; } if (list.indexOf(CRYPTOMINING) != -1) { cat |= AntiTracking.CRYPTOMINING; } return cat; } /* package */ static @CBAntiTracking int stListToAtCat(final String list) { int cat = AntiTracking.NONE; if (list == null) { return cat; } if (list.indexOf(STP) != -1) { cat |= AntiTracking.STP; } return cat; } /* package */ static @CBAntiTracking int etbListToAtCat(final String list) { int cat = AntiTracking.NONE; if (list == null) { return cat; } if (list.indexOf(EMAIL) != -1) { cat |= AntiTracking.EMAIL; } return cat; } /* package */ static @CBSafeBrowsing int errorToSbCat(final long error) { // Match flags with XPCOM ErrorList.h. if (error == 0x805D001FL) { return SafeBrowsing.PHISHING; } if (error == 0x805D001EL) { return SafeBrowsing.MALWARE; } if (error == 0x805D0023L) { return SafeBrowsing.UNWANTED; } if (error == 0x805D0026L) { return SafeBrowsing.HARMFUL; } return SafeBrowsing.NONE; } // Match flags with nsIWebProgressListener.idl. private static final long STATE_COOKIES_LOADED = 0x8000L; private static final long STATE_COOKIES_LOADED_TRACKER = 0x40000L; private static final long STATE_COOKIES_LOADED_SOCIALTRACKER = 0x80000L; private static final long STATE_COOKIES_BLOCKED_TRACKER = 0x20000000L; private static final long STATE_COOKIES_BLOCKED_SOCIALTRACKER = 0x01000000L; private static final long STATE_COOKIES_BLOCKED_ALL = 0x40000000L; private static final long STATE_COOKIES_BLOCKED_FOREIGN = 0x80L; /* package */ static boolean isBlockingGeckoCbCat(final long geckoCat) { return (geckoCat & (STATE_COOKIES_BLOCKED_TRACKER | STATE_COOKIES_BLOCKED_SOCIALTRACKER | STATE_COOKIES_BLOCKED_ALL | STATE_COOKIES_BLOCKED_FOREIGN)) != 0; } /* package */ static @CBCookieBehavior int geckoCatToCbCat(final long geckoCat) { if ((geckoCat & STATE_COOKIES_LOADED) != 0) { // We don't know which setting would actually block this cookie, so // we return the most strict value. return CookieBehavior.ACCEPT_NONE; } if ((geckoCat & STATE_COOKIES_BLOCKED_FOREIGN) != 0) { return CookieBehavior.ACCEPT_FIRST_PARTY; } // If we receive STATE_COOKIES_LOADED_{SOCIAL,}TRACKER we know that this // setting would block this cookie. if ((geckoCat & (STATE_COOKIES_BLOCKED_TRACKER | STATE_COOKIES_BLOCKED_SOCIALTRACKER | STATE_COOKIES_LOADED_TRACKER | STATE_COOKIES_LOADED_SOCIALTRACKER)) != 0) { return CookieBehavior.ACCEPT_NON_TRACKERS; } if ((geckoCat & STATE_COOKIES_BLOCKED_ALL) != 0) { return CookieBehavior.ACCEPT_NONE; } // TODO: There are more reasons why cookies may be blocked. return CookieBehavior.ACCEPT_ALL; } // Cookie Banner Handling feature. public static class CookieBannerMode { /** Do not enable handling cookie banners. */ public static final int COOKIE_BANNER_MODE_DISABLED = 0; /** Only handle banners where selecting "reject all" is possible. */ public static final int COOKIE_BANNER_MODE_REJECT = 1; /** Reject cookies when possible otherwise accept the cookies. */ public static final int COOKIE_BANNER_MODE_REJECT_OR_ACCEPT = 2; protected CookieBannerMode() {} } @Retention(RetentionPolicy.SOURCE) @IntDef({ CookieBannerMode.COOKIE_BANNER_MODE_DISABLED, CookieBannerMode.COOKIE_BANNER_MODE_REJECT, CookieBannerMode.COOKIE_BANNER_MODE_REJECT_OR_ACCEPT, }) public @interface CBCookieBannerMode {} }