Skip to content

Commit 6932ec0

Browse files
authored
Add allowList for Duck Player message handlers (#5053)
Task/Issue URL: https://app.asana.com/0/72649045549333/1208375755367840/f ### Description Only process duck-player related messages if the origin belongs to a given set of domains ### Steps to test this PR _Feature 1_ - [x] Open a YouTube video - [x] Click the button to open in Duck Player - [x] Check the app navigates to Duck Player - [x] Click the settings button - [x] Check native settings are launched
1 parent 6c0eae8 commit 6932ec0

File tree

5 files changed

+36
-8
lines changed

5 files changed

+36
-8
lines changed

content-scope-scripts/content-scope-scripts-impl/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ dependencies {
3333
implementation project(':browser-api')
3434
implementation project(':feature-toggles-api')
3535
implementation project(':js-messaging-api')
36+
implementation project(':duckplayer-api')
3637

3738
anvil project(':anvil-compiler')
3839
implementation project(':anvil-annotations')

content-scope-scripts/content-scope-scripts-impl/src/main/java/com/duckduckgo/contentscopescripts/impl/messaging/ContentScopeScriptsJsMessaging.kt

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,12 @@ package com.duckduckgo.contentscopescripts.impl.messaging
1919
import android.webkit.JavascriptInterface
2020
import android.webkit.WebView
2121
import androidx.core.net.toUri
22+
import com.duckduckgo.common.utils.AppUrl
2223
import com.duckduckgo.common.utils.DispatcherProvider
2324
import com.duckduckgo.contentscopescripts.impl.CoreContentScopeScripts
2425
import com.duckduckgo.di.scopes.FragmentScope
26+
import com.duckduckgo.duckplayer.api.YOUTUBE_HOST
27+
import com.duckduckgo.duckplayer.api.YOUTUBE_MOBILE_HOST
2528
import com.duckduckgo.js.messaging.api.JsCallbackData
2629
import com.duckduckgo.js.messaging.api.JsMessage
2730
import com.duckduckgo.js.messaging.api.JsMessageCallback
@@ -122,12 +125,15 @@ class ContentScopeScriptsJsMessaging @Inject constructor(
122125

123126
inner class DuckPlayerHandler : JsMessageHandler {
124127
override fun process(jsMessage: JsMessage, secret: String, jsMessageCallback: JsMessageCallback?) {
125-
// TODO (cbarreiro): Add again when https://app.asana.com/0/0/1207602010403610/f is fixed
126-
// if (jsMessage.id == null) return
127128
jsMessageCallback?.process(featureName, jsMessage.method, jsMessage.id ?: "", jsMessage.params)
128129
}
129130

130-
override val allowedDomains: List<String> = emptyList()
131+
override val allowedDomains: List<String> = listOf(
132+
AppUrl.Url.HOST,
133+
YOUTUBE_HOST,
134+
YOUTUBE_MOBILE_HOST,
135+
)
136+
131137
override val featureName: String = "duckPlayer"
132138
override val methods: List<String> = listOf(
133139
"getUserValues",

duckplayer/duckplayer-api/src/main/java/com/duckduckgo/duckplayer/api/DuckPlayer.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ import com.duckduckgo.duckplayer.api.PrivatePlayerMode.Disabled
2727
import com.duckduckgo.duckplayer.api.PrivatePlayerMode.Enabled
2828
import kotlinx.coroutines.flow.Flow
2929

30+
const val YOUTUBE_HOST = "youtube.com"
31+
const val YOUTUBE_MOBILE_HOST = "m.youtube.com"
32+
3033
/**
3134
* DuckPlayer interface provides a set of methods for interacting with the DuckPlayer.
3235
*/

duckplayer/duckplayer-impl/src/main/java/com/duckduckgo/duckplayer/impl/DuckPlayerScriptsJsMessaging.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ import logcat.logcat
4343
class DuckPlayerScriptsJsMessaging @Inject constructor(
4444
private val jsMessageHelper: JsMessageHelper,
4545
private val dispatcherProvider: DispatcherProvider,
46+
private val duckPlayer: DuckPlayerInternal,
4647
) : JsMessaging {
4748
private val moshi = Moshi.Builder().add(JSONObjectAdapter()).build()
4849

@@ -119,7 +120,9 @@ class DuckPlayerScriptsJsMessaging @Inject constructor(
119120
jsMessageCallback?.process(featureName, jsMessage.method, jsMessage.id ?: "", jsMessage.params)
120121
}
121122

122-
override val allowedDomains: List<String> = emptyList()
123+
override val allowedDomains: List<String> = listOf(
124+
runBlocking { duckPlayer.getYouTubeEmbedUrl() },
125+
)
123126
override val featureName: String = "duckPlayerPage"
124127
override val methods: List<String> = listOf(
125128
"initialSetup",

duckplayer/duckplayer-impl/src/main/java/com/duckduckgo/duckplayer/impl/RealDuckPlayer.kt

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ import com.duckduckgo.duckplayer.api.DuckPlayer.UserPreferences
3939
import com.duckduckgo.duckplayer.api.PrivatePlayerMode.AlwaysAsk
4040
import com.duckduckgo.duckplayer.api.PrivatePlayerMode.Disabled
4141
import com.duckduckgo.duckplayer.api.PrivatePlayerMode.Enabled
42+
import com.duckduckgo.duckplayer.api.YOUTUBE_HOST
43+
import com.duckduckgo.duckplayer.api.YOUTUBE_MOBILE_HOST
4244
import com.duckduckgo.duckplayer.impl.DuckPlayerPixelName.DUCK_PLAYER_DAILY_UNIQUE_VIEW
4345
import com.duckduckgo.duckplayer.impl.DuckPlayerPixelName.DUCK_PLAYER_OVERLAY_YOUTUBE_IMPRESSIONS
4446
import com.duckduckgo.duckplayer.impl.DuckPlayerPixelName.DUCK_PLAYER_OVERLAY_YOUTUBE_WATCH_HERE
@@ -57,25 +59,34 @@ import kotlinx.coroutines.flow.Flow
5759
import kotlinx.coroutines.flow.map
5860
import kotlinx.coroutines.withContext
5961

60-
private const val YOUTUBE_HOST = "youtube.com"
61-
private const val YOUTUBE_MOBILE_HOST = "m.youtube.com"
6262
private const val DUCK_PLAYER_VIDEO_ID_QUERY_PARAM = "videoID"
6363
private const val DUCK_PLAYER_OPEN_IN_YOUTUBE_PATH = "openInYoutube"
6464
private const val DUCK_PLAYER_DOMAIN = "player"
6565
private const val DUCK_PLAYER_URL_BASE = "$duck://$DUCK_PLAYER_DOMAIN/"
6666
private const val DUCK_PLAYER_ASSETS_PATH = "duckplayer/"
6767
private const val DUCK_PLAYER_ASSETS_INDEX_PATH = "${DUCK_PLAYER_ASSETS_PATH}index.html"
6868

69+
interface DuckPlayerInternal : DuckPlayer {
70+
/**
71+
* Retrieves the YouTube embed URL.
72+
*
73+
* @return The YouTube embed URL.
74+
*/
75+
suspend fun getYouTubeEmbedUrl(): String
76+
}
77+
6978
@SingleInstanceIn(AppScope::class)
70-
@ContributesBinding(AppScope::class)
79+
80+
@ContributesBinding(AppScope::class, boundType = DuckPlayer::class)
81+
@ContributesBinding(AppScope::class, boundType = DuckPlayerInternal::class)
7182
class RealDuckPlayer @Inject constructor(
7283
private val duckPlayerFeatureRepository: DuckPlayerFeatureRepository,
7384
private val duckPlayerFeature: DuckPlayerFeature,
7485
private val pixel: Pixel,
7586
private val duckPlayerLocalFilesPath: DuckPlayerLocalFilesPath,
7687
private val mimeTypeMap: MimeTypeMap,
7788
private val dispatchers: DispatcherProvider,
78-
) : DuckPlayer {
89+
) : DuckPlayerInternal {
7990

8091
private var shouldForceYTNavigation = false
8192
private var shouldHideOverlay = false
@@ -391,6 +402,10 @@ class RealDuckPlayer @Inject constructor(
391402
}
392403
}
393404

405+
override suspend fun getYouTubeEmbedUrl(): String {
406+
return duckPlayerFeatureRepository.getYouTubeEmbedUrl()
407+
}
408+
394409
override suspend fun willNavigateToDuckPlayer(
395410
destinationUrl: Uri,
396411
): Boolean {

0 commit comments

Comments
 (0)