Skip to content

Commit

Permalink
Integrate privacy dashboard (#5593)
Browse files Browse the repository at this point in the history
Task/Issue URL:
https://app.asana.com/0/1205008441501016/1208836754662808

### Description

### Steps to test this PR

_Pre-requisites_
`npm i github:duckduckgo/privacy-dashboard#pr-releases/pr-300`


_Feature 1_
- [ ] Visit
https://privacy-test-pages.site/security/badware/phishing.html
- [ ] Accept the risk and visit site
- [ ] Click on Privacy Shield
- [ ] Check a modified version of privacy dashboard is shown reflecting
the malicious site status

### UI changes
| Before  | After |
| ------ | ----- |
!(Upload before screenshot)|(Upload after screenshot)|
  • Loading branch information
CrisBarreiro authored Feb 6, 2025
1 parent 59b117a commit 3ebea1b
Show file tree
Hide file tree
Showing 14 changed files with 62 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ package com.duckduckgo.app.browser.omnibar.animations

import com.airbnb.lottie.LottieAnimationView
import com.duckduckgo.app.browser.R
import com.duckduckgo.app.global.model.PrivacyShield.MALICIOUS
import com.duckduckgo.app.global.model.PrivacyShield.PROTECTED
import com.duckduckgo.app.global.model.PrivacyShield.UNPROTECTED
import com.duckduckgo.app.global.model.PrivacyShield.WARNING
import com.duckduckgo.common.ui.store.AppTheme
import org.junit.Test
import org.mockito.kotlin.mock
Expand Down Expand Up @@ -80,28 +80,28 @@ class LottiePrivacyShieldAnimationHelperTest {
}

@Test
fun whenLightModeAndPrivacyShieldWarningThenUseLightAnimation() {
fun whenLightModeAndPrivacyShieldMaliciousThenUseLightAnimation() {
val holder: LottieAnimationView = mock()
val appTheme: AppTheme = mock()
whenever(appTheme.isLightModeEnabled()).thenReturn(true)
val testee = LottiePrivacyShieldAnimationHelper(appTheme)

testee.setAnimationView(holder, WARNING)
testee.setAnimationView(holder, MALICIOUS)

verify(holder).setAnimation(R.raw.unprotected_shield)
verify(holder).progress = 1.0f
verify(holder).setAnimation(R.raw.alert_red)
verify(holder).progress = 0.0f
}

@Test
fun whenDarkModeAndPrivacyShieldWarningThenUseDarkAnimation() {
fun whenDarkModeAndPrivacyShieldMaliciousThenUseDarkAnimation() {
val holder: LottieAnimationView = mock()
val appTheme: AppTheme = mock()
whenever(appTheme.isLightModeEnabled()).thenReturn(false)
val testee = LottiePrivacyShieldAnimationHelper(appTheme)

testee.setAnimationView(holder, WARNING)
testee.setAnimationView(holder, MALICIOUS)

verify(holder).setAnimation(R.raw.dark_unprotected_shield)
verify(holder).progress = 1.0f
verify(holder).setAnimation(R.raw.alert_red_dark)
verify(holder).progress = 0.0f
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ package com.duckduckgo.app.browser.omnibar.animations
import com.airbnb.lottie.LottieAnimationView
import com.duckduckgo.app.browser.R
import com.duckduckgo.app.global.model.PrivacyShield
import com.duckduckgo.app.global.model.PrivacyShield.MALICIOUS
import com.duckduckgo.app.global.model.PrivacyShield.PROTECTED
import com.duckduckgo.app.global.model.PrivacyShield.UNKNOWN
import com.duckduckgo.app.global.model.PrivacyShield.UNPROTECTED
import com.duckduckgo.app.global.model.PrivacyShield.WARNING
import com.duckduckgo.common.ui.store.AppTheme
import com.duckduckgo.di.scopes.AppScope
import com.squareup.anvil.annotations.ContributesBinding
Expand Down Expand Up @@ -54,10 +54,10 @@ class LottiePrivacyShieldAnimationHelper @Inject constructor(val appTheme: AppTh
UNKNOWN -> {
Timber.i("Shield: UNKNOWN")
}
WARNING -> {
val res = if (appTheme.isLightModeEnabled()) R.raw.unprotected_shield else R.raw.dark_unprotected_shield
MALICIOUS -> {
val res = if (appTheme.isLightModeEnabled()) R.raw.alert_red else R.raw.alert_red_dark
holder.setAnimation(res)
holder.progress = 1.0f
holder.progress = 0.0f
Timber.i("Shield: WARNING")
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import androidx.annotation.WorkerThread
import androidx.core.net.toUri
import com.duckduckgo.app.browser.UriString
import com.duckduckgo.app.browser.certificates.BypassedSSLCertificatesRepository
import com.duckduckgo.app.global.model.PrivacyShield.MALICIOUS
import com.duckduckgo.app.global.model.PrivacyShield.PROTECTED
import com.duckduckgo.app.global.model.PrivacyShield.UNKNOWN
import com.duckduckgo.app.global.model.PrivacyShield.UNPROTECTED
Expand Down Expand Up @@ -167,6 +168,7 @@ class SiteMonitor(
userAllowList = domain?.let { isAllowListed(it) } ?: false
if (duckPlayer.isDuckPlayerUri(url)) return UNKNOWN
if (userAllowList || !isHttps) return UNPROTECTED
if (maliciousSiteStatus != null) return MALICIOUS

if (!fullSiteDetailsAvailable) {
Timber.i("Shield: not fullSiteDetailsAvailable for $domain")
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/raw/alert_red.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"v":"5.7.12","fr":24,"ip":0,"op":24,"w":130,"h":40,"nm":"error @40px_light","ddd":0,"assets":[{"id":"comp_0","nm":"Alert_Red","layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Exclamation Mark","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[12,12,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-1.016,0],[0.108,-1.01],[0,0],[0.46,0],[0.049,0.457]],"o":[[-0.108,-1.01],[1.016,0],[0,0],[-0.049,0.457],[-0.46,0],[0,0]],"v":[[-1.699,-5.459],[0,-7.35],[1.699,-5.459],[0.895,2.046],[0,2.85],[-0.895,2.046]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":5,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[0,-0.828],[0.828,0],[0,0.828],[-0.828,0]],"o":[[0,0.828],[-0.828,0],[0,-0.828],[0.828,0]],"v":[[1.5,5.85],[0,7.35],[-1.5,5.85],[0,4.35]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":5,"nm":"Merge Paths 2","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape","np":5,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":96,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Circle","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[12,12,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-6.075,0],[0,6.075],[6.075,0],[0,-6.075]],"o":[[6.075,0],[0,-6.075],[-6.075,0],[0,6.075]],"v":[[0,11],[11,0],[0,-11],[-11,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333337307,0.06274510175,0.145098045468,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":96,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Alert_Red","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[22,20,0],"ix":2,"l":2},"a":{"a":0,"k":[12,12,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":24,"h":24,"ip":0,"op":96,"st":0,"bm":0}],"markers":[{"tm":0,"cm":"","dr":0},{"tm":80,"cm":"","dr":0}]}
1 change: 1 addition & 0 deletions app/src/main/res/raw/alert_red_dark.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"v":"5.7.12","fr":24,"ip":0,"op":24,"w":130,"h":40,"nm":"error @40px_dark","ddd":0,"assets":[{"id":"comp_0","nm":"Alert_Red_Dark","layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Exclamation Mark","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[12,12,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-1.016,0],[0.108,-1.01],[0,0],[0.46,0],[0.049,0.457]],"o":[[-0.108,-1.01],[1.016,0],[0,0],[-0.049,0.457],[-0.46,0],[0,0]],"v":[[-1.699,-5.459],[0,-7.35],[1.699,-5.459],[0.895,2.046],[0,2.85],[-0.895,2.046]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":5,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[0,-0.828],[0.828,0],[0,0.828],[-0.828,0]],"o":[[0,0.828],[-0.828,0],[0,-0.828],[0.828,0]],"v":[[1.5,5.85],[0,7.35],[-1.5,5.85],[0,4.35]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":5,"nm":"Merge Paths 2","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape","np":5,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":96,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Circle","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[12,12,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-6.075,0],[0,6.075],[6.075,0],[0,-6.075]],"o":[[6.075,0],[0,-6.075],[-6.075,0],[0,6.075]],"v":[[0,11],[11,0],[0,-11],[-11,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.329411764706,0.352941176471,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":96,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Alert_Red_Dark","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[22,20,0],"ix":2,"l":2},"a":{"a":0,"k":[12,12,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":24,"h":24,"ip":0,"op":96,"st":0,"bm":0}],"markers":[{"tm":32,"cm":"","dr":0},{"tm":45,"cm":"","dr":0}]}
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,7 @@ class OmnibarLayoutViewModelTest {

@Test
fun whenPrivacyShieldChangedToWarningThenViewStateCorrect() = runTest {
val privacyShield = PrivacyShield.WARNING
val privacyShield = PrivacyShield.MALICIOUS
testee.onPrivacyShieldChanged(privacyShield)

testee.viewState.test {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@ package com.duckduckgo.app.global.model
enum class PrivacyShield {
PROTECTED,
UNPROTECTED,
WARNING,
MALICIOUS,
UNKNOWN,
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"@duckduckgo/autoconsent": "^12.8.0",
"@duckduckgo/autofill": "github:duckduckgo/duckduckgo-autofill#16.2.0",
"@duckduckgo/content-scope-scripts": "github:duckduckgo/content-scope-scripts#7.16.0",
"@duckduckgo/privacy-dashboard": "github:duckduckgo/privacy-dashboard#8.1.0",
"@duckduckgo/privacy-dashboard": "github:duckduckgo/privacy-dashboard#8.4.0",
"@duckduckgo/privacy-reference-tests": "github:duckduckgo/privacy-reference-tests#1738159777"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ class PrivacyDashboardHybridViewModel @Inject constructor(
val protectionStatus: ProtectionStatusViewState,
val cookiePromptManagementStatus: CookiePromptManagementState,
val remoteFeatureSettings: RemoteFeatureSettingsViewState,
val maliciousSiteStatus: String? = null,
)

data class ProtectionStatusViewState(
Expand Down Expand Up @@ -289,6 +290,7 @@ class PrivacyDashboardHybridViewModel @Inject constructor(
protectionStatus = protectionStatusViewStateMapper.mapFromSite(site),
cookiePromptManagementStatus = autoconsentStatusViewStateMapper.mapFromSite(site),
remoteFeatureSettings = createRemoteFeatureSettings(),
maliciousSiteStatus = site.maliciousSiteStatus?.name?.lowercase(),
),
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ class PrivacyDashboardRenderer(
val cookiePromptManagementStatusJson = cookiePromptManagementStatusAdapter.toJson(viewState.cookiePromptManagementStatus)
webView.evaluateJavascript("javascript:onChangeConsentManaged($cookiePromptManagementStatusJson);", null)

val maliciousStateJson = """{"kind": "${viewState.maliciousSiteStatus}"}"""
webView.evaluateJavascript("javascript:onChangeMaliciousSiteStatus($maliciousStateJson);", null)

// remote feature settings
val remoteFeatureSettingsAdapter = moshi.adapter(RemoteFeatureSettingsViewState::class.java)
val remoteFeatureSettingsJson = remoteFeatureSettingsAdapter.toJson(viewState.remoteFeatureSettings)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ class PrivacyDashboardRendererTest {

testee.render(aViewState())

verify(spyWebView, times(8)).evaluateJavascript(captor.capture(), eq(null))
verify(spyWebView, times(9)).evaluateJavascript(captor.capture(), eq(null))

assertNotNull(captor.allValues.find { it.startsWith("javascript:onChangeLocale") })
assertNotNull(captor.allValues.find { it.startsWith("javascript:onChangeFeatureSettings") })
Expand All @@ -123,6 +123,7 @@ class PrivacyDashboardRendererTest {
assertNotNull(captor.allValues.find { it.startsWith("javascript:onChangeUpgradedHttps") })
assertNotNull(captor.allValues.find { it.startsWith("javascript:onChangeRequestData") })
assertNotNull(captor.allValues.find { it.startsWith("javascript:onChangeConsentManaged") })
assertNotNull(captor.allValues.find { it.startsWith("javascript:onChangeMaliciousSiteStatus") })
}

fun aViewState() = ViewState(
Expand Down

0 comments on commit 3ebea1b

Please sign in to comment.