Skip to content

Commit

Permalink
Add allowList for Duck Player message handlers (#5053)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
CrisBarreiro authored Oct 2, 2024
1 parent 6c0eae8 commit 6932ec0
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ dependencies {
implementation project(':browser-api')
implementation project(':feature-toggles-api')
implementation project(':js-messaging-api')
implementation project(':duckplayer-api')

anvil project(':anvil-compiler')
implementation project(':anvil-annotations')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,12 @@ package com.duckduckgo.contentscopescripts.impl.messaging
import android.webkit.JavascriptInterface
import android.webkit.WebView
import androidx.core.net.toUri
import com.duckduckgo.common.utils.AppUrl
import com.duckduckgo.common.utils.DispatcherProvider
import com.duckduckgo.contentscopescripts.impl.CoreContentScopeScripts
import com.duckduckgo.di.scopes.FragmentScope
import com.duckduckgo.duckplayer.api.YOUTUBE_HOST
import com.duckduckgo.duckplayer.api.YOUTUBE_MOBILE_HOST
import com.duckduckgo.js.messaging.api.JsCallbackData
import com.duckduckgo.js.messaging.api.JsMessage
import com.duckduckgo.js.messaging.api.JsMessageCallback
Expand Down Expand Up @@ -122,12 +125,15 @@ class ContentScopeScriptsJsMessaging @Inject constructor(

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

override val allowedDomains: List<String> = emptyList()
override val allowedDomains: List<String> = listOf(
AppUrl.Url.HOST,
YOUTUBE_HOST,
YOUTUBE_MOBILE_HOST,
)

override val featureName: String = "duckPlayer"
override val methods: List<String> = listOf(
"getUserValues",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ import com.duckduckgo.duckplayer.api.PrivatePlayerMode.Disabled
import com.duckduckgo.duckplayer.api.PrivatePlayerMode.Enabled
import kotlinx.coroutines.flow.Flow

const val YOUTUBE_HOST = "youtube.com"
const val YOUTUBE_MOBILE_HOST = "m.youtube.com"

/**
* DuckPlayer interface provides a set of methods for interacting with the DuckPlayer.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import logcat.logcat
class DuckPlayerScriptsJsMessaging @Inject constructor(
private val jsMessageHelper: JsMessageHelper,
private val dispatcherProvider: DispatcherProvider,
private val duckPlayer: DuckPlayerInternal,
) : JsMessaging {
private val moshi = Moshi.Builder().add(JSONObjectAdapter()).build()

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

override val allowedDomains: List<String> = emptyList()
override val allowedDomains: List<String> = listOf(
runBlocking { duckPlayer.getYouTubeEmbedUrl() },
)
override val featureName: String = "duckPlayerPage"
override val methods: List<String> = listOf(
"initialSetup",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ import com.duckduckgo.duckplayer.api.DuckPlayer.UserPreferences
import com.duckduckgo.duckplayer.api.PrivatePlayerMode.AlwaysAsk
import com.duckduckgo.duckplayer.api.PrivatePlayerMode.Disabled
import com.duckduckgo.duckplayer.api.PrivatePlayerMode.Enabled
import com.duckduckgo.duckplayer.api.YOUTUBE_HOST
import com.duckduckgo.duckplayer.api.YOUTUBE_MOBILE_HOST
import com.duckduckgo.duckplayer.impl.DuckPlayerPixelName.DUCK_PLAYER_DAILY_UNIQUE_VIEW
import com.duckduckgo.duckplayer.impl.DuckPlayerPixelName.DUCK_PLAYER_OVERLAY_YOUTUBE_IMPRESSIONS
import com.duckduckgo.duckplayer.impl.DuckPlayerPixelName.DUCK_PLAYER_OVERLAY_YOUTUBE_WATCH_HERE
Expand All @@ -57,25 +59,34 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.withContext

private const val YOUTUBE_HOST = "youtube.com"
private const val YOUTUBE_MOBILE_HOST = "m.youtube.com"
private const val DUCK_PLAYER_VIDEO_ID_QUERY_PARAM = "videoID"
private const val DUCK_PLAYER_OPEN_IN_YOUTUBE_PATH = "openInYoutube"
private const val DUCK_PLAYER_DOMAIN = "player"
private const val DUCK_PLAYER_URL_BASE = "$duck://$DUCK_PLAYER_DOMAIN/"
private const val DUCK_PLAYER_ASSETS_PATH = "duckplayer/"
private const val DUCK_PLAYER_ASSETS_INDEX_PATH = "${DUCK_PLAYER_ASSETS_PATH}index.html"

interface DuckPlayerInternal : DuckPlayer {
/**
* Retrieves the YouTube embed URL.
*
* @return The YouTube embed URL.
*/
suspend fun getYouTubeEmbedUrl(): String
}

@SingleInstanceIn(AppScope::class)
@ContributesBinding(AppScope::class)

@ContributesBinding(AppScope::class, boundType = DuckPlayer::class)
@ContributesBinding(AppScope::class, boundType = DuckPlayerInternal::class)
class RealDuckPlayer @Inject constructor(
private val duckPlayerFeatureRepository: DuckPlayerFeatureRepository,
private val duckPlayerFeature: DuckPlayerFeature,
private val pixel: Pixel,
private val duckPlayerLocalFilesPath: DuckPlayerLocalFilesPath,
private val mimeTypeMap: MimeTypeMap,
private val dispatchers: DispatcherProvider,
) : DuckPlayer {
) : DuckPlayerInternal {

private var shouldForceYTNavigation = false
private var shouldHideOverlay = false
Expand Down Expand Up @@ -391,6 +402,10 @@ class RealDuckPlayer @Inject constructor(
}
}

override suspend fun getYouTubeEmbedUrl(): String {
return duckPlayerFeatureRepository.getYouTubeEmbedUrl()
}

override suspend fun willNavigateToDuckPlayer(
destinationUrl: Uri,
): Boolean {
Expand Down

0 comments on commit 6932ec0

Please sign in to comment.