Skip to content

Commit f8b7255

Browse files
authored
Add https summary
1 parent dc4bfc5 commit f8b7255

File tree

48 files changed

+426
-134
lines changed

Some content is hidden

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

48 files changed

+426
-134
lines changed

app/src/androidTest/java/com/duckduckgo/app/browser/BrowserViewModelTest.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import org.mockito.Mockito.verify
3737
class BrowserViewModelTest {
3838

3939
@get:Rule
40+
@Suppress("unused")
4041
var instantTaskExecutorRule = InstantTaskExecutorRule()
4142

4243
@Mock

app/src/androidTest/java/com/duckduckgo/app/global/UriExtensionTest.kt

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@
1717
package com.duckduckgo.app.global
1818

1919
import android.net.Uri
20-
import org.junit.Assert.assertEquals
21-
import org.junit.Assert.assertNull
20+
import org.junit.Assert.*
2221
import org.junit.Test
2322

2423

@@ -38,26 +37,57 @@ class UriExtensionTest {
3837

3938
@Test
4039
fun whenUriBeginsWithWwwThenBaseHostReturnsWithoutWww() {
41-
val url = "http://www.somehost.com"
42-
assertEquals("somehost.com", Uri.parse(url).baseHost())
40+
val url = "http://www.example.com"
41+
assertEquals("example.com", Uri.parse(url).baseHost)
4342
}
4443

4544
@Test
4645
fun whenUriDoesNotBeginWithWwwThenBaseHosReturnsWithSameHost() {
47-
val url = "http://somehost.com"
48-
assertEquals("somehost.com", Uri.parse(url).baseHost())
46+
val url = "http://example.com"
47+
assertEquals("example.com", Uri.parse(url).baseHost)
4948
}
5049

5150
@Test
5251
fun whenUriDoesNotHaveASchemeThenBaseHostStillResolvesHost() {
53-
val url = "www.somehost.com"
54-
assertEquals("somehost.com", Uri.parse(url).baseHost())
52+
val url = "www.example.com"
53+
assertEquals("example.com", Uri.parse(url).baseHost)
5554
}
5655

5756
@Test
5857
fun whenUriContainsInvalidHostThenBaseHostIsNull() {
5958
val url = "about:blank"
60-
assertNull(Uri.parse(url).baseHost())
59+
assertNull(Uri.parse(url).baseHost)
6160
}
6261

62+
@Test
63+
fun whenUriIsHttpIrrespectiveOfCaseThenIsHttpIsTrue() {
64+
assertTrue(Uri.parse("http://example.com").isHttp)
65+
assertTrue(Uri.parse("HTTP://example.com").isHttp)
66+
}
67+
68+
@Test
69+
fun whenUriIsHttpsThenIsHttpIsFalse() {
70+
assertFalse(Uri.parse("https://example.com").isHttp)
71+
}
72+
73+
@Test
74+
fun whenUriIsMalformedThenIsHttpIsFalse() {
75+
assertFalse(Uri.parse("[example com]").isHttp)
76+
}
77+
78+
@Test
79+
fun whenUriIsHttpsIrrespectiveOfCaseThenIsHttpsIsTrue() {
80+
assertTrue(Uri.parse("https://example.com").isHttps)
81+
assertTrue(Uri.parse("HTTPS://example.com").isHttps)
82+
}
83+
84+
@Test
85+
fun whenUriIsHttpThenIsHttpsIsFalse() {
86+
assertFalse(Uri.parse("http://example.com").isHttps)
87+
}
88+
89+
@Test
90+
fun whenUriIsMalformedThenIsHtpsIsFalse() {
91+
assertFalse(Uri.parse("[example com]").isHttps)
92+
}
6393
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*
2+
* Copyright (c) 2017 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.app.privacydashboard
18+
19+
import android.arch.core.executor.testing.InstantTaskExecutorRule
20+
import android.arch.lifecycle.Observer
21+
import android.support.test.InstrumentationRegistry
22+
import com.duckduckgo.app.browser.R
23+
import com.duckduckgo.app.privacymonitor.HttpsStatus
24+
import com.duckduckgo.app.privacymonitor.PrivacyMonitor
25+
import com.nhaarman.mockito_kotlin.mock
26+
import com.nhaarman.mockito_kotlin.whenever
27+
import org.junit.After
28+
import org.junit.Assert.assertEquals
29+
import org.junit.Before
30+
import org.junit.Rule
31+
import org.junit.Test
32+
import org.mockito.Mock
33+
34+
class PrivacyDashboardViewModelTest {
35+
36+
@get:Rule
37+
@Suppress("unused")
38+
var instantTaskExecutorRule = InstantTaskExecutorRule()
39+
40+
@Mock
41+
private val viewStateObserver: Observer<PrivacyDashboardViewModel.ViewState> = mock()
42+
43+
@Mock
44+
private val monitor: PrivacyMonitor = mock()
45+
46+
private lateinit var testee: PrivacyDashboardViewModel
47+
48+
@Before
49+
fun before() {
50+
testee = PrivacyDashboardViewModel(InstrumentationRegistry.getTargetContext())
51+
testee.viewState.observeForever(viewStateObserver)
52+
whenever(monitor.https).thenReturn(HttpsStatus.SECURE)
53+
}
54+
55+
@After
56+
fun after() {
57+
testee.viewState.removeObserver(viewStateObserver)
58+
}
59+
60+
@Test
61+
fun whenHttpsStatusIsSecureThenTextAndIconReflectSame() {
62+
whenever(monitor.https).thenReturn(HttpsStatus.SECURE)
63+
testee.updatePrivacyMonitor(monitor)
64+
assertEquals(getStringResource(R.string.httpsGood), testee.viewState.value?.httpsText)
65+
assertEquals(R.drawable.dashboard_https_good, testee.viewState.value?.httpsIcon)
66+
}
67+
68+
@Test
69+
fun whenHttpsStatusIsMixedThenTextAndIconReflectSame() {
70+
whenever(monitor.https).thenReturn(HttpsStatus.MIXED)
71+
testee.updatePrivacyMonitor(monitor)
72+
assertEquals(getStringResource(R.string.httpsMixed), testee.viewState.value?.httpsText)
73+
assertEquals(R.drawable.dashboard_https_neutral, testee.viewState.value?.httpsIcon)
74+
}
75+
76+
@Test
77+
fun whenHttpsStatusIsNoneThenTextAndIconReflectSame() {
78+
whenever(monitor.https).thenReturn(HttpsStatus.NONE)
79+
testee.updatePrivacyMonitor(monitor)
80+
assertEquals(getStringResource(R.string.httpsBad), testee.viewState.value?.httpsText)
81+
assertEquals(R.drawable.dashboard_https_bad, testee.viewState.value?.httpsIcon)
82+
}
83+
84+
@Test
85+
fun whenNoTrackersNetworksThenTrackerNetworkTextShowsZero() {
86+
whenever(monitor.trackerNetworkCount).thenReturn(0)
87+
testee.updatePrivacyMonitor(monitor)
88+
assertEquals("0 Tracker Networks Blocked", testee.viewState.value?.trackerNetworksText)
89+
}
90+
91+
@Test
92+
fun whenTenTrackersNetworksThenTrackerNetworkTextShowsTen() {
93+
whenever(monitor.trackerNetworkCount).thenReturn(10)
94+
testee.updatePrivacyMonitor(monitor)
95+
assertEquals("10 Tracker Networks Blocked", testee.viewState.value?.trackerNetworksText)
96+
}
97+
98+
private fun getStringResource(id: Int): String {
99+
return InstrumentationRegistry.getTargetContext().getString(id)
100+
}
101+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright (c) 2017 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.app.privacymonitor
18+
19+
import com.duckduckgo.app.trackerdetection.model.NetworkTrackers
20+
import org.junit.Assert.assertEquals
21+
import org.junit.Test
22+
23+
class SiteMonitorInstrumentationTests {
24+
25+
companion object {
26+
private const val httpDocument = "http://example.com"
27+
private const val httpsDocument = "https://example.com"
28+
private const val malformesDocument = "[example com]"
29+
}
30+
31+
@Test
32+
fun whenUrlIsHttpsThenHttpsStatusIsSecure() {
33+
val testee = SiteMonitor(httpsDocument, NetworkTrackers())
34+
assertEquals(HttpsStatus.SECURE, testee.https)
35+
}
36+
37+
@Test
38+
fun whenUrlIsHttpThenHttpsStatusIsNone() {
39+
val testee = SiteMonitor(httpDocument, NetworkTrackers())
40+
assertEquals(HttpsStatus.NONE, testee.https)
41+
}
42+
43+
@Test
44+
fun whenUrlIsHttpsWithHttpResourcesThenHttpsStatusIsMixed() {
45+
val testee = SiteMonitor(httpsDocument, NetworkTrackers())
46+
testee.hasHttpResources = true
47+
assertEquals(HttpsStatus.MIXED, testee.https)
48+
}
49+
50+
@Test
51+
fun whenUrlIsMalformedThenHttpsStatusIsNone() {
52+
val testee = SiteMonitor(malformesDocument, NetworkTrackers())
53+
assertEquals(HttpsStatus.NONE, testee.https)
54+
}
55+
}

app/src/main/java/com/duckduckgo/app/browser/BrowserActivity.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import android.view.Menu
2727
import android.view.MenuItem
2828
import android.view.View
2929
import android.view.inputmethod.EditorInfo
30+
import android.webkit.WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE
3031
import android.widget.TextView
3132
import com.duckduckgo.app.browser.BrowserViewModel.NavigationCommand.LANDING_PAGE
3233
import com.duckduckgo.app.browser.omnibar.OnBackKeyListener
@@ -176,6 +177,7 @@ class BrowserActivity : DuckDuckGoActivity() {
176177
useWideViewPort = true
177178
builtInZoomControls = true
178179
displayZoomControls = false
180+
mixedContentMode = MIXED_CONTENT_COMPATIBILITY_MODE
179181
setSupportZoom(true)
180182
}
181183

app/src/main/java/com/duckduckgo/app/browser/BrowserViewModel.kt

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import android.arch.lifecycle.MutableLiveData
2020
import android.arch.lifecycle.ViewModel
2121
import com.duckduckgo.app.browser.omnibar.OmnibarEntryConverter
2222
import com.duckduckgo.app.global.SingleLiveEvent
23-
import com.duckduckgo.app.sitemonitor.SiteMonitor
23+
import com.duckduckgo.app.privacymonitor.SiteMonitor
2424
import com.duckduckgo.app.trackerdetection.model.NetworkTrackers
2525
import com.duckduckgo.app.trackerdetection.model.TrackingEvent
2626
import timber.log.Timber
@@ -86,7 +86,7 @@ class BrowserViewModel(
8686
override fun loadingStarted() {
8787
Timber.v("Loading started")
8888
viewState.value = currentViewState().copy(isLoading = true)
89-
siteMonitor = SiteMonitor(networkTrackers)
89+
siteMonitor = null
9090
}
9191

9292
override fun loadingFinished() {
@@ -102,13 +102,19 @@ class BrowserViewModel(
102102
newViewState = newViewState.copy(url = lastQuery)
103103
}
104104
viewState.value = newViewState
105-
siteMonitor?.url = url
105+
if (url != null) {
106+
siteMonitor = SiteMonitor(url, networkTrackers)
107+
}
106108
}
107109

108110
override fun trackerDetected(event: TrackingEvent) {
109111
siteMonitor?.trackerDetected(event)
110112
}
111113

114+
override fun pageHasHttpResources() {
115+
siteMonitor?.hasHttpResources = true
116+
}
117+
112118
private fun currentViewState(): ViewState = viewState.value!!
113119

114120

app/src/main/java/com/duckduckgo/app/browser/BrowserWebViewClient.kt

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import android.webkit.WebResourceRequest
2323
import android.webkit.WebResourceResponse
2424
import android.webkit.WebView
2525
import android.webkit.WebViewClient
26+
import com.duckduckgo.app.global.isHttp
2627
import com.duckduckgo.app.trackerdetection.TrackerDetector
2728
import com.duckduckgo.app.trackerdetection.model.ResourceType
2829
import com.duckduckgo.app.trackerdetection.model.TrackingEvent
@@ -64,6 +65,10 @@ class BrowserWebViewClient @Inject constructor(
6465
override fun shouldInterceptRequest(view: WebView, request: WebResourceRequest): WebResourceResponse? {
6566
Timber.v("Intercepting resource ${request.url}")
6667

68+
if (request.url != null && request.url.isHttp) {
69+
webViewClientListener?.pageHasHttpResources()
70+
}
71+
6772
if (view.elementClicked() == request.url.toString()) {
6873
return null
6974
}
@@ -82,12 +87,12 @@ class BrowserWebViewClient @Inject constructor(
8287
webViewClientListener?.trackerDetected(TrackingEvent(url, documentUrl, true))
8388
return true
8489
}
85-
90+
8691
return false
8792
}
8893

8994
private fun WebView.elementClicked(): String? {
90-
return safeHitTestResult()?.extra
95+
return safeHitTestResult().extra
9196
}
9297

9398
/**

app/src/main/java/com/duckduckgo/app/browser/WebViewClientListener.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,5 @@ interface WebViewClientListener {
2424
fun progressChanged(newProgress: Int)
2525
fun urlChanged(url: String?)
2626
fun trackerDetected(event: TrackingEvent)
27+
fun pageHasHttpResources()
2728
}

app/src/main/java/com/duckduckgo/app/global/UriExtension.kt

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ fun Uri.withScheme(): Uri {
3131
* Tries to resolve a host (even if the scheme is missing), returning
3232
* a basic host without the "www" subdomain.
3333
*/
34-
fun Uri.baseHost(): String? {
35-
return withScheme().host?.removePrefix("www.")
36-
}
34+
val Uri.baseHost: String?
35+
get() = withScheme().host?.removePrefix("www.")
36+
37+
val Uri.isHttp: Boolean
38+
get() = scheme?.equals(UrlScheme.http, true) ?: false
39+
40+
val Uri.isHttps: Boolean
41+
get() = scheme?.equals(UrlScheme.https, true) ?: false

app/src/main/java/com/duckduckgo/app/global/UriString.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ import android.net.Uri
2121
class UriString {
2222
companion object {
2323
fun sameOrSubdomain(child: String, parent: String): Boolean {
24-
val childHost = Uri.parse(child)?.baseHost() ?: return false
25-
val parentHost = Uri.parse(parent)?.baseHost() ?: return false
24+
val childHost = Uri.parse(child)?.baseHost ?: return false
25+
val parentHost = Uri.parse(parent)?.baseHost ?: return false
2626
return parentHost == childHost || childHost.endsWith(".$parentHost")
2727
}
2828
}

0 commit comments

Comments
 (0)