8000 Integrate AppTP with privacy remote config (#1832) · xpcom-bsd/Android-1@39c6a29 · GitHub
[go: up one dir, main page]

Skip to content

Commit 39c6a29

Browse files
authored
Integrate AppTP with privacy remote config (duckduckgo#1832)
Task/Issue URL: https://app.asana.com/0/72649045549333/1202005414608950/f ### Description _NOTE: originally stacked PR onto duckduckgo#1830 -> #1829_ Integrates AppTP with privacy remote config ### Steps to test this PR _Test internal builds_ - [x] fresh install from INTERNAL debug builds - [x] launch the app - [x] verify the `apptp_remote_config.db` contains a table dubbed `vpn_config_toggles` - [x] verify the `vpn_config_toggles` table contains `ipv6Support`, `privateDnsSupport`, `networkSwitchHandling` and `badHealthMitigation` entries - [x] verify all entries are false (`0`) for both `enabled` and `isManualOverride` columns except for `badHealthMitigation` that should have `enabled` set to true (`1`) - [x] go to Settings -> AppTP dev settings - [x] verify all toggles are disabled - [x] go to Settings -> App Tracking Protection and enable AppTP - [x] go to Settings -> AppTP dev settings - [x] verify all toggles are in state enabled - [x] verify only `VPN debug logging`, `Bad health monitoring` and `Bad health mitigation action` toggles are ON, remaining ones should be OFF - [x] filter logcat by `Dropping ipv6` - [x] open instagram and verify logs appear (dropping IPv6 packets) - you may need to in cellular if you don't see logs on WIFI - [x] close instagram - [x] go to Settings -> AppTP dev settings and toggle IPv6 support ON - [x] open instagram and verify no logs appear - [x] go to Settings -> AppTP dev settings and toggle IPv6 support OFF - [x] filter logcat by `private dns` - [x] go to Android settings and search for private DNS - [x] set `Private DNS provider hostname` to `one.one.one.one` - [x] verify `Private DNS support is disabled...skip` appear - [x] set Private DNS to off - [x] verify `Private DNS support is disabled...skip` appear - [x] go to Settings -> AppTP dev settings and toggle `Private DNS support` ON - [x] set `Private DNS provider hostname` to `one.one.one.one` - [x] verify `Setting private DNS: ...` appear and VPN is restarted (look at the key icon in the status bar) - [x] set Private DNS to off - [x] verify `Setting private DNS: ...` DO NOT appear and VPN is restarted (look at the key icon in the status bar) - [x] go to Settings -> AppTP dev settings and toggle `IPv6 Support` and `private DNS support` ON - [x] In AS, open `privacy_config.json` file and set the `version` to `1648641758000` to force reload the remote settings on app launch - [x] Filter logcat by `AppTpFeatureConfigImpl` - [x] rebuild and install the app - [x] launch the app - [x] verify `Skip setEnabled...` appear for both `Ipv6Support` and `PrivateDnsSupport` - [x] go to Settings -> AppTP dev settings - [x] verify both IPv6 and privacy support toggles are still ON - [x] verify opening instagram does not log any `Dropping ipv6...` message in logcat _Test PLAY build_ - [x] Modify `AppTPHealthMonitor:simulateHealthStatusIfEnabled` method, so that the first `if` condition is `if (!appBuildConfig.isDebug)` - [x] build and fresn install from PLAY debug build - [x] Enable AppTp - grab invice code from [here](https://app.asana.com/0/0/1201184915504678/f) - [x] Verify in logcat ipv6 packets are dropped when opening instagram - [x] Verify in logcat `Private DNS support is disabled...skip` appears when trying to set private DNS from Android settings - [x] Go to Settings -> App Tracking Protection screen -> overflo menu -> Diagnostics = [ ] filter logcat by `AppBadHealthStateHandler` - [x] scroll down and click on `BAD HEALTH` button - [x] verify the `AppBadHealthStateHandler: Restarting the VPN....` message appears in logcat after a while - [x] Click in `GOOD HEALTH` and wait for `no alerts` message - [x] Click on `CRITICAL HEALTH` - [x] verify that after a while `Restarting the VPN...` meessage appears and the diagnostics screen is killed (becauase we killed that process) _Test app update_ - [ ] install from develop branch the INTERNAL build - [ ] launch app and enable AppTP - [ ] verify there is no `apptp_remote_config.db` database - [ ] go to Settings -> AppTP settings - [ ] verify `VPN debug logging` and `Bad health monitoring` and `Bad health mitigation` toggles are ON - [ ] verify the rest of toggles are OFF - [ ] click on `View diagnostics Data` - [ ] scroll down and click on `CRITICAL HEALTH` - [ ] verify the current activity is killed (it can take a while) - this is because the VPN process is restarted - [ ] verify AppTP is enabled - [ ] update the app from this branch (INTERNAL build) - [ ] verify the `apptp_remote_config.db` exists and it has an EMPTY `vpn_config_toggles` table - [ ] go to Settings -> AppTP settings - [ ] verify `VPN debug logging` and `Bad health monitoring` and `Bad health mitigation` toggles are ON - [ ] click on `View diagnostics Data` - [ ] scroll down and click on `CRITICAL HEALTH` - [ ] verify the current activity is killed (it can take a while) - this is because the VPN process is restarted - [ ] verify AppTP is enabled - [ ] go to Settings -> AppTP settings and enable `IPv6 support` - [ ] verify the `vpn_config_toggles` db table contains the `ipv6Support` entry with `enabled` and `isManuallyOverride` columns set to `1` - [ ] force kill the app and relaunch it - [ ] go to Settings -> AppTP settings - [ ] verify `ipv6 support` toggle is still ON - [ ] verify the `vpn_config_toggles` db table contains the `ipv6Support` entry with `enabled` and `isManuallyOverride` columns set to `1` _Test remote config updates_ - [ ] install from this branch the INTERNAL build - [ ] open the app and enable AppTP - [ ] go to Settings -> AppTP dev settings - [ ] verify all toggles under `CONFIG` section are OFF - [ ] verify the `vpn_config_toggles` table in the `apptp_remote_config.db` also has entries for all toggles (only badHealthMitigation` entry is enabled) - [ ] use Charles to update the remote config file and update the ipv6 config to enabled and update the version - [ ] kill and restart the app - [ ] go to Settings -> AppTP dev settings - [ ] verify the ipv6 toggle is ON - [ ] verify the `vpn_config_toggles` table in the `apptp_remote_config.db` also has the ipv6 config as enabled and with `isManuallyOverride` set to `0`
1 parent 8183280 commit 39c6a29

File tree

54 files changed

+1968
-327
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+1968
-327
lines changed

app/src/internal/java/com/duckduckgo/app/flipper/FlipperInitializer.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import com.duckduckgo.di.scopes.AppScope
2525
import com.facebook.flipper.android.AndroidFlipperClient
2626
import com.facebook.flipper.core.FlipperPlugin
2727
import com.facebook.flipper.plugins.databases.DatabasesFlipperPlugin
28+
import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin
2829
import com.facebook.soloader.SoLoader
2930
import com.squareup.anvil.annotations.ContributesMultibinding
3031
import timber.log.Timber
@@ -48,6 +49,7 @@ class FlipperInitializer @Inject constructor(
4849

4950
// Common device plugins
5051
addPlugin(DatabasesFlipperPlugin(context))
52+
addPlugin(SharedPreferencesFlipperPlugin(context))
5153

5254
start()
5355
}

feature-toggles/feature-toggles-api/src/main/java/com/duckduckgo/feature/toggles/api/FeatureToggle.kt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,25 @@ interface FeatureToggle {
3434
*/
3535
interface FeatureName {
3636
val value: String
37+
38+
companion object {
39+
/**
40+
* Utility function to create a [FeatureName] from the passed in [block] lambda
41+
* instead of using the anonymous `object : FeatureName` syntax.
42+
*
43+
* Usage:
44+
*
45+
* ```kotlin
46+
* val feature = FeatureName {
47+
*
48+
* }
49+
* ```
50+
*/
51+
inline operator fun invoke(crossinline block: () -> String): FeatureName {
52+
return object : FeatureName {
53+
override val value: String
54+
get() = block()
55+
}
56+
}
57+
}
3758
}

privacy-config/privacy-config-api/src/main/java/com/duckduckgo/privacy/config/api/PrivacyFeatureName.kt

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,3 @@ enum class PrivacyFeatureName(override val value: String) : FeatureName {
2929
TrackingParametersFeatureName("trackingParameters"),
3030
AutofillFeatureName("autofill"),
3131
}
32-
33-
/**
34-
* Convenience method to get the [PrivacyFeatureName] from its [String] value
35-
*/
36-
fun privacyFeatureValueOf(value: String): PrivacyFeatureName? {
37-
return PrivacyFeatureName.values().find { it.value == value }
38-
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright (c) 2022 DuckDuckGo
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.duckduckgo.privacy.config.api
18+
19+
import com.duckduckgo.feature.toggles.api.FeatureName
20+
21+
/**
22+
* Implement this interface and contribute it as a multibinding to get called upon downloading remote privacy config
23+
*
24+
* Usage:
25+
*
26+
* ```kotlin
27+
* @ContributesMultibinding(AppScope::class)
28+
* class MuFeaturePlugin @Inject constructor(...) : PrivacyFeaturePlugin {
29+
*
30+
* }
31+
* ```
32+
*/
33+
interface PrivacyFeaturePlugin {
34+
/**
35+
* @return `true` when the feature config was stored, otherwise `false`
36+
*/
37+
fun store(
38+
name: FeatureName,
39+
jsonString: String
40+
): Boolean
41+
42+
/**
43+
* @return the [FeatureName] of this feature
44+
*/
45+
val featureName: FeatureName
46+
}

privacy-config/privacy-config-impl/src/main/java/com/duckduckgo/privacy/config/impl/PrivacyConfigPersister.kt

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ package com.duckduckgo.privacy.config.impl
1919
import androidx.annotation.WorkerThread
2020
import com.duckduckgo.app.global.plugins.PluginPoint
2121
import com.duckduckgo.di.scopes.AppScope
22-
import com.duckduckgo.privacy.config.api.privacyFeatureValueOf
22+
import com.duckduckgo.feature.toggles.api.FeatureName
2323
import com.duckduckgo.privacy.config.impl.models.JsonPrivacyConfig
24-
import com.duckduckgo.privacy.config.impl.plugins.PrivacyFeaturePlugin
24+
import com.duckduckgo.privacy.config.api.PrivacyFeaturePlugin
2525
import com.duckduckgo.privacy.config.store.PrivacyConfig
2626
import com.duckduckgo.privacy.config.store.PrivacyConfigDatabase
2727
import com.duckduckgo.privacy.config.store.PrivacyConfigRepository
@@ -58,10 +58,8 @@ class RealPrivacyConfigPersister @Inject constructor(
5858
unprotectedTemporaryRepository.updateAll(jsonPrivacyConfig.unprotectedTemporary)
5959
jsonPrivacyConfig.features.forEach { feature ->
6060
feature.value?.let { jsonObject ->
61-
privacyFeaturePluginPoint.getPlugins().forEach { plugin ->
62-
privacyFeatureValueOf(feature.key)?.let {
63-
plugin.store(it, jsonObject.toString())
64-
}
61+
privacyFeaturePluginPoint.getPlugins().firstOrNull { feature.key == it.featureName.value }?.let { featurePlugin ->
62+
featurePlugin.store(FeatureName { feature.key }, jsonObject.toString())
6563
}
6664
}
6765
}

privacy-config/privacy-config-impl/src/main/java/com/duckduckgo/privacy/config/impl/di/PrivacyConfigModule.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import com.duckduckgo.di.DaggerSet
2626
import com.duckduckgo.di.scopes.AppScope
2727
import com.duckduckgo.privacy.config.impl.network.JSONObjectAdapter
2828
import com.duckduckgo.privacy.config.impl.network.PrivacyConfigService
29-
import com.duckduckgo.privacy.config.impl.plugins.PrivacyFeaturePlugin
29+
import com.duckduckgo.privacy.config.api.PrivacyFeaturePlugin
3030
import com.duckduckgo.privacy.config.impl.plugins.PrivacyFeaturePluginPoint
3131
import com.duckduckgo.privacy.config.store.ALL_MIGRATIONS
3232
import com.duckduckgo.privacy.config.store.PrivacyConfigDatabase
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Copyright (c) 2022 DuckDuckGo
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.duckduckgo.privacy.config.impl.features
18+
19+
import com.duckduckgo.privacy.config.api.PrivacyFeatureName
20+
21+
/**
22+
* Convenience method to get the [PrivacyFeatureName] from its [String] value
23+
*/
24+
fun privacyFeatureValueOf(value: String): PrivacyFeatureName? {
25+
return PrivacyFeatureName.values().find { it.value == value }
26+
}

privacy-config/privacy-config-impl/src/main/java/com/duckduckgo/privacy/config/impl/features/amplinks/AmpLinksPlugin.kt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@
1717
package com.duckduckgo.privacy.config.impl.features.amplinks
1818

1919
import com.duckduckgo.di.scopes.AppScope
20+
import com.duckduckgo.feature.toggles.api.FeatureName
2021
import com.duckduckgo.privacy.config.api.PrivacyFeatureName
21-
import com.duckduckgo.privacy.config.impl.plugins.PrivacyFeaturePlugin
22+
import com.duckduckgo.privacy.config.impl.features.privacyFeatureValueOf
23+
import com.duckduckgo.privacy.config.api.PrivacyFeaturePlugin
2224
import com.duckduckgo.privacy.config.store.*
2325
import com.duckduckgo.privacy.config.store.features.amplinks.AmpLinksRepository
2426
import com.squareup.anvil.annotations.ContributesMultibinding
@@ -32,7 +34,9 @@ class AmpLinksPlugin @Inject constructor(
3234
private val privacyFeatureTogglesRepository: PrivacyFeatureTogglesRepository
3335
) : PrivacyFeaturePlugin {
3436

35-
override fun store(name: PrivacyFeatureName, jsonString: String): Boolean {
37+
override fun store(name: FeatureName, jsonString: String): Boolean {
38+
@Suppress("NAME_SHADOWING")
39+
val name = privacyFeatureValueOf(name.value)
3640
if (name == featureName) {
3741
val moshi = Moshi.Builder().build()
3842
val jsonAdapter: JsonAdapter<AmpLinksFeature> =

privacy-config/privacy-config-impl/src/main/java/com/duckduckgo/privacy/config/impl/features/autofill/AutofillPlugin.kt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@
1717
package com.duckduckgo.privacy.config.impl.features.autofill
1818

1919
import com.duckduckgo.di.scopes.AppScope
20+
import com.duckduckgo.feature.toggles.api.FeatureName
2021
import com.duckduckgo.privacy.config.api.PrivacyFeatureName
21-
import com.duckduckgo.privacy.config.impl.plugins.PrivacyFeaturePlugin
22+
import com.duckduckgo.privacy.config.impl.features.privacyFeatureValueOf
23+
import com.duckduckgo.privacy.config.api.PrivacyFeaturePlugin
2224
import com.duckduckgo.privacy.config.store.AutofillExceptionEntity
2325
import com.duckduckgo.privacy.config.store.PrivacyFeatureToggles
2426
import com.duckduckgo.privacy.config.store.PrivacyFeatureTogglesRepository
@@ -35,9 +37,11 @@ class AutofillPlugin @Inject constructor(
3537
) : PrivacyFeaturePlugin {
3638

3739
override fun store(
38-
name: PrivacyFeatureName,
40+
name: FeatureName,
3941
jsonString: String
4042
): Boolean {
43+
@Suppress("NAME_SHADOWING")
44+
val name = privacyFeatureValueOf(name.value)
4145
if (name == featureName) {
4246
val autofillExceptions = mutableListOf<AutofillExceptionEntity>()
4347
val moshi = Moshi.Builder().build()

privacy-config/privacy-config-impl/src/main/java/com/duckduckgo/privacy/config/impl/features/contentblocking/ContentBlockingPlugin.kt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@
1717
package com.duckduckgo.privacy.config.impl.features.contentblocking
1818

1919
import com.duckduckgo.di.scopes.AppScope
20+
import com.duckduckgo.feature.toggles.api.FeatureName
2021
import com.duckduckgo.privacy.config.api.PrivacyFeatureName
21-
import com.duckduckgo.privacy.config.impl.plugins.PrivacyFeaturePlugin
22+
import com.duckduckgo.privacy.config.impl.features.privacyFeatureValueOf
23+
import com.duckduckgo.privacy.config.api.PrivacyFeaturePlugin
2224
import com.duckduckgo.privacy.config.store.ContentBlockingExceptionEntity
2325
import com.duckduckgo.privacy.config.store.PrivacyFeatureToggles
2426
import com.duckduckgo.privacy.config.store.PrivacyFeatureTogglesRepository
@@ -35,9 +37,11 @@ class ContentBlockingPlugin @Inject constructor(
3537
) : PrivacyFeaturePlugin {
3638

3739
override fun store(
38-
name: PrivacyFeatureName,
40+
name: FeatureName,
3941
jsonString: String
4042
): Boolean {
43+
@Suppress("NAME_SHADOWING")
44+
val name = privacyFeatureValueOf(name.value)
4145
if (name == featureName) {
4246
val contentBlockingExceptions = mutableListOf<ContentBlockingExceptionEntity>()
4347
val moshi = Moshi.Builder().build()

0 commit comments

Comments
 (0)
0