From 05a4faec7871678b6103aa04ce89113f8e12d49e Mon Sep 17 00:00:00 2001 From: Tiger Oakes Date: Fri, 13 Sep 2019 14:43:54 -0700 Subject: [PATCH] Add tryGetHostFromUrl and update ExceptionDomains --- .../mozilla/fenix/AppRequestInterceptor.kt | 11 +--- .../fenix/exceptions/ExceptionDomains.kt | 66 ++++++++++--------- .../fenix/exceptions/ExceptionsFragment.kt | 16 ++--- .../main/java/org/mozilla/fenix/ext/String.kt | 10 +-- .../library/history/HistoryDataSource.kt | 5 +- .../QuickSettingsSheetDialogFragment.kt | 15 +---- .../trackingprotection/TrackerBuckets.kt | 10 +-- .../TrackingProtectionPanelDialogFragment.kt | 19 ++---- .../java/org/mozilla/fenix/ext/StringTest.kt | 16 ++--- 9 files changed, 74 insertions(+), 94 deletions(-) diff --git a/app/src/main/java/org/mozilla/fenix/AppRequestInterceptor.kt b/app/src/main/java/org/mozilla/fenix/AppRequestInterceptor.kt index c548cab01..331250b06 100644 --- a/app/src/main/java/org/mozilla/fenix/AppRequestInterceptor.kt +++ b/app/src/main/java/org/mozilla/fenix/AppRequestInterceptor.kt @@ -13,16 +13,11 @@ import org.mozilla.fenix.components.metrics.Event import org.mozilla.fenix.exceptions.ExceptionDomains import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.settings -import java.net.MalformedURLException -import java.net.URL +import org.mozilla.fenix.ext.tryGetHostFromUrl class AppRequestInterceptor(private val context: Context) : RequestInterceptor { override fun onLoadRequest(session: EngineSession, uri: String): RequestInterceptor.InterceptionResponse? { - val host = try { - URL(uri).host - } catch (e: MalformedURLException) { - uri - } + val host = uri.tryGetHostFromUrl() adjustTrackingProtection(host, context, session) @@ -35,7 +30,7 @@ class AppRequestInterceptor(private val context: Context) : RequestInterceptor { } private fun adjustTrackingProtection(host: String, context: Context, session: EngineSession) { - val trackingProtectionException = ExceptionDomains.load(context).contains(host) + val trackingProtectionException = ExceptionDomains(context).load().contains(host) val trackingProtectionEnabled = context.settings.shouldUseTrackingProtection if (trackingProtectionException || !trackingProtectionEnabled) { session.disableTrackingProtection() diff --git a/app/src/main/java/org/mozilla/fenix/exceptions/ExceptionDomains.kt b/app/src/main/java/org/mozilla/fenix/exceptions/ExceptionDomains.kt index 6c4cee957..828bc2c03 100644 --- a/app/src/main/java/org/mozilla/fenix/exceptions/ExceptionDomains.kt +++ b/app/src/main/java/org/mozilla/fenix/exceptions/ExceptionDomains.kt @@ -6,73 +6,79 @@ package org.mozilla.fenix.exceptions import android.content.Context import android.content.SharedPreferences +import mozilla.components.support.ktx.android.content.PreferencesHolder +import mozilla.components.support.ktx.android.content.stringPreference /** * Contains functionality to manage custom domains for allow-list. */ -object ExceptionDomains { - private const val PREFERENCE_NAME = "exceptions" - private const val KEY_DOMAINS = "exceptions_domains" - private const val SEPARATOR = "@<;>@" +class ExceptionDomains(context: Context) : PreferencesHolder { - private var exceptions: List? = null + override val preferences: SharedPreferences = + context.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE) + + private var domains by stringPreference(KEY_DOMAINS, default = "") /** * Loads the previously added/saved custom domains from preferences. * - * @param context the application context * @return list of custom domains */ - fun load(context: Context): List { + fun load(): List { if (exceptions == null) { - exceptions = (preferences(context) - .getString(KEY_DOMAINS, "") ?: "") - .split(SEPARATOR) - .filter { !it.isEmpty() } + exceptions = domains.split(SEPARATOR).filter { it.isNotEmpty() } } - return exceptions ?: listOf() + return exceptions.orEmpty() } /** * Saves the provided domains to preferences. * - * @param context the application context * @param domains list of domains */ - fun save(context: Context, domains: List) { + fun save(domains: List) { exceptions = domains - preferences(context) - .edit() - .putString(KEY_DOMAINS, domains.joinToString(separator = SEPARATOR)) - .apply() + this.domains = domains.joinToString(separator = SEPARATOR) } /** * Adds the provided domain to preferences. * - * @param context the application context * @param domain the domain to add */ - fun add(context: Context, domain: String) { - val domains = mutableListOf() - domains.addAll(load(context)) - domains.add(domain) - - save(context, domains) + fun add(domain: String) { + save(domains = load() + domain) } /** * Removes the provided domain from preferences. * - * @param context the application context * @param domains the domain to remove */ - fun remove(context: Context, domains: List) { - save(context, load(context) - domains) + fun remove(domains: List) { + save(domains = load() - domains) } - private fun preferences(context: Context): SharedPreferences = - context.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE) + /** + * Adds or removes the provided domain from preferences. + * + * If present, the domain will be removed. Otherwise, it will be added. + */ + fun toggle(domain: String) { + if (domain in load()) { + remove(listOf(domain)) + } else { + add(domain) + } + } + + companion object { + private const val PREFERENCE_NAME = "exceptions" + private const val KEY_DOMAINS = "exceptions_domains" + private const val SEPARATOR = "@<;>@" + + private var exceptions: List? = null + } } diff --git a/app/src/main/java/org/mozilla/fenix/exceptions/ExceptionsFragment.kt b/app/src/main/java/org/mozilla/fenix/exceptions/ExceptionsFragment.kt index 7d06e3a5f..a9ea7c1f0 100644 --- a/app/src/main/java/org/mozilla/fenix/exceptions/ExceptionsFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/exceptions/ExceptionsFragment.kt @@ -66,15 +66,17 @@ class ExceptionsFragment : Fragment() { private fun deleteAllItems() { viewLifecycleOwner.lifecycleScope.launch(IO) { - val domains = ExceptionDomains.load(context!!) - ExceptionDomains.remove(context!!, domains) + ExceptionDomains(requireContext()).run { + val domains = load() + remove(domains) + } reloadData() } } private fun deleteOneItem(item: ExceptionsItem) { viewLifecycleOwner.lifecycleScope.launch(IO) { - ExceptionDomains.remove(context!!, listOf(item.url)) + ExceptionDomains(requireContext()).remove(listOf(item.url)) reloadData() } } @@ -89,12 +91,8 @@ class ExceptionsFragment : Fragment() { } private fun loadAndMapExceptions(): List { - return ExceptionDomains.load(context!!) - .map { item -> - ExceptionsItem( - item - ) - } + return ExceptionDomains(requireContext()).load() + .map { item -> ExceptionsItem(item) } } private suspend fun reloadData() { diff --git a/app/src/main/java/org/mozilla/fenix/ext/String.kt b/app/src/main/java/org/mozilla/fenix/ext/String.kt index df7108780..eed77ff39 100644 --- a/app/src/main/java/org/mozilla/fenix/ext/String.kt +++ b/app/src/main/java/org/mozilla/fenix/ext/String.kt @@ -7,9 +7,9 @@ package org.mozilla.fenix.ext import android.content.Context import androidx.core.net.toUri import kotlinx.coroutines.runBlocking +import mozilla.components.support.ktx.android.net.hostWithoutCommonPrefixes import java.net.MalformedURLException import java.net.URL -import mozilla.components.support.ktx.android.net.hostWithoutCommonPrefixes /** * Replaces the keys with the values with the map provided. @@ -21,13 +21,13 @@ fun String.replace(pairs: Map): String { } /** - * Try to parse and get host part if this [String] is valid URL. - * Returns **null** otherwise. + * Tries to parse and get host part if this [String] is valid URL. + * Otherwise returns the string. */ -fun String?.getHostFromUrl(): String? = try { +fun String.tryGetHostFromUrl(): String = try { URL(this).host } catch (e: MalformedURLException) { - null + this } /** diff --git a/app/src/main/java/org/mozilla/fenix/library/history/HistoryDataSource.kt b/app/src/main/java/org/mozilla/fenix/library/history/HistoryDataSource.kt index f7d45fcae..f6e371968 100644 --- a/app/src/main/java/org/mozilla/fenix/library/history/HistoryDataSource.kt +++ b/app/src/main/java/org/mozilla/fenix/library/history/HistoryDataSource.kt @@ -7,7 +7,7 @@ package org.mozilla.fenix.library.history import androidx.paging.ItemKeyedDataSource import mozilla.components.concept.storage.VisitInfo import org.mozilla.fenix.components.history.PagedHistoryProvider -import org.mozilla.fenix.ext.getHostFromUrl +import org.mozilla.fenix.ext.tryGetHostFromUrl class HistoryDataSource( private val historyProvider: PagedHistoryProvider @@ -44,8 +44,7 @@ class HistoryDataSource( return { id, visit -> val title = visit.title ?.takeIf(String::isNotEmpty) - ?: visit.url.getHostFromUrl() - ?: visit.url + ?: visit.url.tryGetHostFromUrl() HistoryItem(offset + id, title, visit.url, visit.visitTime) } diff --git a/app/src/main/java/org/mozilla/fenix/settings/quicksettings/QuickSettingsSheetDialogFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/quicksettings/QuickSettingsSheetDialogFragment.kt index 70c1b23e2..d8dffa0e1 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/quicksettings/QuickSettingsSheetDialogFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/quicksettings/QuickSettingsSheetDialogFragment.kt @@ -39,12 +39,11 @@ import org.mozilla.fenix.browser.BrowserFragment import org.mozilla.fenix.exceptions.ExceptionDomains import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.requireComponents +import org.mozilla.fenix.ext.tryGetHostFromUrl import org.mozilla.fenix.mvi.ActionBusFactory import org.mozilla.fenix.mvi.getAutoDisposeObservable import org.mozilla.fenix.mvi.getManagedEmitter import org.mozilla.fenix.settings.PhoneFeature -import java.net.MalformedURLException -import java.net.URL import com.google.android.material.R as MaterialR private const val REQUEST_CODE_QUICK_SETTINGS_PERMISSIONS = 4 @@ -155,17 +154,9 @@ class QuickSettingsSheetDialogFragment : AppCompatDialogFragment() { requestCode == REQUEST_CODE_QUICK_SETTINGS_PERMISSIONS && grantResults.all { it == PERMISSION_GRANTED } private fun toggleTrackingProtection(context: Context, url: String) { - val host = try { - URL(url).host - } catch (e: MalformedURLException) { - url - } + val host = url.tryGetHostFromUrl() lifecycleScope.launch { - if (!ExceptionDomains.load(context).contains(host)) { - ExceptionDomains.add(context, host) - } else { - ExceptionDomains.remove(context, listOf(host)) - } + ExceptionDomains(context).toggle(host) } } diff --git a/app/src/main/java/org/mozilla/fenix/trackingprotection/TrackerBuckets.kt b/app/src/main/java/org/mozilla/fenix/trackingprotection/TrackerBuckets.kt index 9aa12a49a..c9c074744 100644 --- a/app/src/main/java/org/mozilla/fenix/trackingprotection/TrackerBuckets.kt +++ b/app/src/main/java/org/mozilla/fenix/trackingprotection/TrackerBuckets.kt @@ -10,7 +10,7 @@ import mozilla.components.concept.engine.EngineSession.TrackingProtectionPolicy. import mozilla.components.concept.engine.EngineSession.TrackingProtectionPolicy.TrackingCategory.FINGERPRINTING import mozilla.components.concept.engine.EngineSession.TrackingProtectionPolicy.TrackingCategory.SOCIAL import mozilla.components.concept.engine.content.blocking.Tracker -import org.mozilla.fenix.ext.getHostFromUrl +import org.mozilla.fenix.ext.tryGetHostFromUrl import org.mozilla.fenix.trackingprotection.TrackingProtectionCategory.CRYPTOMINERS import org.mozilla.fenix.trackingprotection.TrackingProtectionCategory.FINGERPRINTERS import org.mozilla.fenix.trackingprotection.TrackingProtectionCategory.SOCIAL_MEDIA_TRACKERS @@ -57,21 +57,21 @@ class TrackerBuckets { when { CRYPTOMINING in item.trackingCategories -> { map[CRYPTOMINERS] = map[CRYPTOMINERS].orEmpty() + - (item.url.getHostFromUrl() ?: item.url) + item.url.tryGetHostFromUrl() } FINGERPRINTING in item.trackingCategories -> { map[FINGERPRINTERS] = map[FINGERPRINTERS].orEmpty() + - (item.url.getHostFromUrl() ?: item.url) + item.url.tryGetHostFromUrl() } SOCIAL in item.trackingCategories -> { map[SOCIAL_MEDIA_TRACKERS] = map[SOCIAL_MEDIA_TRACKERS].orEmpty() + - (item.url.getHostFromUrl() ?: item.url) + item.url.tryGetHostFromUrl() } AD in item.trackingCategories || SOCIAL in item.trackingCategories || ANALYTICS in item.trackingCategories -> { map[TRACKING_CONTENT] = map[TRACKING_CONTENT].orEmpty() + - (item.url.getHostFromUrl() ?: item.url) + item.url.tryGetHostFromUrl() } } } diff --git a/app/src/main/java/org/mozilla/fenix/trackingprotection/TrackingProtectionPanelDialogFragment.kt b/app/src/main/java/org/mozilla/fenix/trackingprotection/TrackingProtectionPanelDialogFragment.kt index 1b89a6e83..6dfb545b2 100644 --- a/app/src/main/java/org/mozilla/fenix/trackingprotection/TrackingProtectionPanelDialogFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/trackingprotection/TrackingProtectionPanelDialogFragment.kt @@ -33,8 +33,7 @@ import org.mozilla.fenix.exceptions.ExceptionDomains import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.nav import org.mozilla.fenix.ext.requireComponents -import java.net.MalformedURLException -import java.net.URL +import org.mozilla.fenix.ext.tryGetHostFromUrl class TrackingProtectionPanelDialogFragment : AppCompatDialogFragment(), BackHandler { @@ -154,20 +153,12 @@ class TrackingProtectionPanelDialogFragment : AppCompatDialogFragment(), BackHan } private fun toggleTrackingProtection(isEnabled: Boolean) { - context?.let { - val host = try { - URL(url).host - } catch (e: MalformedURLException) { - url - } + context?.let { context -> + val host = url.tryGetHostFromUrl() lifecycleScope.launch { - if (!ExceptionDomains.load(it).contains(host)) { - ExceptionDomains.add(it, host) - } else { - ExceptionDomains.remove(it, listOf(host)) - } + ExceptionDomains(context).toggle(host) } - it.components.useCases.sessionUseCases.reload.invoke() + context.components.useCases.sessionUseCases.reload.invoke() } trackingProtectionStore.dispatch(TrackingProtectionAction.TrackerBlockingChanged(isEnabled)) } diff --git a/app/src/test/java/org/mozilla/fenix/ext/StringTest.kt b/app/src/test/java/org/mozilla/fenix/ext/StringTest.kt index 7b5623b81..fe2a3552b 100644 --- a/app/src/test/java/org/mozilla/fenix/ext/StringTest.kt +++ b/app/src/test/java/org/mozilla/fenix/ext/StringTest.kt @@ -2,10 +2,10 @@ package org.mozilla.fenix.ext import kotlinx.coroutines.ObsoleteCoroutinesApi import mozilla.components.support.test.robolectric.testContext -import org.mozilla.fenix.TestApplication +import org.junit.Assert.assertEquals import org.junit.Test import org.junit.runner.RunWith -import org.junit.Assert.assertEquals +import org.mozilla.fenix.TestApplication import org.robolectric.RobolectricTestRunner import org.robolectric.annotation.Config @@ -16,31 +16,31 @@ import org.robolectric.annotation.Config class StringTest { @Test - fun `Replace`() { + fun replace() { val chars = mapOf("Mozilla Corporation" to "moco", "Mozilla Foundation" to "mofo") - var sentence = "Mozilla Corporation and Mozilla Foundation are committed to the future of the internet" + val sentence = "Mozilla Corporation and Mozilla Foundation are committed to the future of the internet" val new = sentence.replace(chars) assertEquals(new, "moco and mofo are committed to the future of the internet") } @Test - fun `Get Host From Url`() { + fun `Try Get Host From Url`() { val urlTest = "http://www.example.com:1080/docs/resource1.html" - var new = urlTest.getHostFromUrl() + val new = urlTest.tryGetHostFromUrl() assertEquals(new, "www.example.com") } @Test fun `Url To Trimmed Host`() { val urlTest = "http://www.example.com:1080/docs/resource1.html" - var new = urlTest.urlToTrimmedHost(testContext) + val new = urlTest.urlToTrimmedHost(testContext) assertEquals(new, "example") } @Test fun `Simplified Url`() { val urlTest = "https://www.amazon.com" - var new = urlTest.simplifiedUrl() + val new = urlTest.simplifiedUrl() assertEquals(new, "amazon.com") } }