diff options
Diffstat (limited to 'mobile/android/geckoview/src/main/java/org/mozilla/geckoview/ContentBlocking.java')
-rw-r--r-- | mobile/android/geckoview/src/main/java/org/mozilla/geckoview/ContentBlocking.java | 1689 |
1 files changed, 1689 insertions, 0 deletions
diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/ContentBlocking.java b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/ContentBlocking.java new file mode 100644 index 0000000000..7d284611b4 --- /dev/null +++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/ContentBlocking.java @@ -0,0 +1,1689 @@ +/* -*- 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", + "goog-passwordwhite-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<String, SafeBrowsingProvider> 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<Settings> { + @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 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; + } + + /** + * 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<String> mAt = + new Pref<String>( + "urlclassifier.trackingTable", ContentBlocking.catToAtPref(AntiTracking.DEFAULT)); + /* package */ final Pref<Boolean> mCm = + new Pref<Boolean>("privacy.trackingprotection.cryptomining.enabled", false); + /* package */ final Pref<String> mCmList = + new Pref<String>( + "urlclassifier.features.cryptomining.blacklistTables", + ContentBlocking.catToCmListPref(AntiTracking.NONE)); + /* package */ final Pref<Boolean> mFp = + new Pref<Boolean>("privacy.trackingprotection.fingerprinting.enabled", false); + /* package */ final Pref<String> mFpList = + new Pref<String>( + "urlclassifier.features.fingerprinting.blacklistTables", + ContentBlocking.catToFpListPref(AntiTracking.NONE)); + /* package */ final Pref<Boolean> mSt = + new Pref<Boolean>("privacy.socialtracking.block_cookies.enabled", false); + /* package */ final Pref<Boolean> mStStrict = + new Pref<Boolean>("privacy.trackingprotection.socialtracking.enabled", false); + /* package */ final Pref<String> mStList = + new Pref<String>( + "urlclassifier.features.socialtracking.annotate.blacklistTables", + ContentBlocking.catToStListPref(AntiTracking.NONE)); + + /* package */ final Pref<Boolean> mSbMalware = + new Pref<Boolean>("browser.safebrowsing.malware.enabled", true); + /* package */ final Pref<Boolean> mSbPhishing = + new Pref<Boolean>("browser.safebrowsing.phishing.enabled", true); + /* package */ final Pref<Integer> mCookieBehavior = + new Pref<Integer>("network.cookie.cookieBehavior", CookieBehavior.ACCEPT_NON_TRACKERS); + /* package */ final Pref<Integer> mCookieBehaviorPrivateMode = + new Pref<Integer>( + "network.cookie.cookieBehavior.pbmode", CookieBehavior.ACCEPT_NON_TRACKERS); + /* package */ final Pref<Boolean> mCookiePurging = + new Pref<Boolean>("privacy.purge_trackers.enabled", false); + + /* package */ final Pref<Boolean> mEtpEnabled = + new Pref<Boolean>("privacy.trackingprotection.annotate_channels", false); + /* package */ final Pref<Boolean> mEtpStrict = + new Pref<Boolean>("privacy.annotate_channels.strict_list.enabled", false); + + /* package */ final Pref<Integer> mCbhMode = + new Pref<Integer>( + "cookiebanners.service.mode", CookieBannerMode.COOKIE_BANNER_MODE_DISABLED); + /* package */ final Pref<Integer> mCbhModePrivateBrowsing = + new Pref<Integer>( + "cookiebanners.service.mode.privateBrowsing", + CookieBannerMode.COOKIE_BANNER_MODE_REJECT); + + /* package */ final Pref<Boolean> mChbDetectOnlyMode = + new Pref<Boolean>("cookiebanners.service.detectOnly", false); + + /* package */ final Pref<String> 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<String> 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<SafeBrowsingProvider> getSafeBrowsingProviders() { + return Collections.unmodifiableCollection(mSafeBrowsingProviders.values()); + } + + /** + * Sets the collection of {@link SafeBrowsingProvider} for this runtime. + * + * <p>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 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.catToStListPref(cat)); + 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()); + } + + /** + * 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; + } + + /** + * 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<Settings> CREATOR = + new Parcelable.Creator<Settings>() { + @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. <br> + * <br> + * This class can be used to modify existing configuration for SafeBrowsing providers or to add a + * custom SafeBrowsing provider to the app. <br> + * <br> + * 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}. <br> + * <br> + * This class is immutable, once constructed its values cannot be changed. <br> + * <br> + * 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: <br> + * + * <pre><code> + * 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); + * </code></pre> + * + * This will override the configuration. <br> + * <br> + * You can also add a custom SafeBrowsing provider using the {@link #withName} method. For + * example, to add a custom provider that provides the list <code>testprovider-phish-digest256 + * </code> do the following: <br> + * + * <pre><code> + * 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(); + * </code></pre> + * + * And then add the custom provider (adding optionally existing providers): <br> + * + * <pre><code> + * 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); + * </code></pre> + * + * And set the list in the phishing configuration <br> + * + * <pre><code> + * runtime.getContentBlocking().setSafeBrowsingPhishingTable( + * "testprovider-phish-digest256", + * // Existing configuration + * "goog-phish-proto"); + * </code></pre> + * + * Note that any list present in the phishing or malware tables need to appear in one safe + * browsing provider's {@link #getLists} property. + * + * <p>See also <a href="https://developers.google.com/safe-browsing/v4">safe-browsing/v4</a>. + */ + @AnyThread + public static class SafeBrowsingProvider extends RuntimeSettings { + private static final String ROOT = "browser.safebrowsing.provider."; + + private final String mName; + + /* package */ final Pref<String> mVersion; + /* package */ final Pref<String> mLists; + /* package */ final Pref<String> mUpdateUrl; + /* package */ final Pref<String> mGetHashUrl; + /* package */ final Pref<String> mReportUrl; + /* package */ final Pref<String> mReportPhishingMistakeUrl; + /* package */ final Pref<String> mReportMalwareMistakeUrl; + /* package */ final Pref<String> mAdvisoryUrl; + /* package */ final Pref<String> mAdvisoryName; + /* package */ final Pref<String> mDataSharingUrl; + /* package */ final Pref<Boolean> mDataSharingEnabled; + + /** + * Creates a {@link SafeBrowsingProvider.Builder} for a provider with the given name. + * + * <p>Note: the <code>mozilla</code> 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 <code>name="mozilla"</code> + */ + @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. + * + * <p>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. + * + * <p>See also <a + * href="https://developers.google.com/safe-browsing/v4/reference/rest/v4/threatListUpdates/fetch"> + * v4/threadListUpdates/fetch </a>. + * + * @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. + * + * <p>See also <a + * href="https://developers.google.com/safe-browsing/v4/reference/rest/v4/fullHashes/find"> + * v4/fullHashes/find </a>. + * + * @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 <code>true</code> 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. + * + * <p>See also <a + * href="https://developers.google.com/safe-browsing/v4/reference/rest/v4/threatListUpdates/fetch"> + * v4/threadListUpdates/fetch </a>. + * + * @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. + * + * <p>See also <a + * href="https://developers.google.com/safe-browsing/v4/reference/rest/v4/fullHashes/find"> + * v4/fullHashes/find </a>. + * + * @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 <code>true</code> if the browser should whare threat data with the provider, <code> + * false</code> 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<SafeBrowsingProvider> CREATOR = + new Parcelable.Creator<SafeBrowsingProvider>() { + @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 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; + + 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.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.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"; + + /* 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 String catToStListPref(@CBAntiTracking final int cat) { + final StringBuilder builder = new StringBuilder(); + + if ((cat & AntiTracking.STP) != 0) { + builder.append(STP).append(","); + } + if (builder.length() == 0) { + return ""; + } + // Trim final ','. + return builder.substring(0, builder.length() - 1); + } + + /* 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 @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 {} +} |