From f1d892f8dc9f9ad0f91cb09be181ca680e3960ac Mon Sep 17 00:00:00 2001 From: katherine <414924+kabliz@users.noreply.github.com> Date: Wed, 23 Oct 2024 16:25:01 -0700 Subject: [PATCH] [APT-10650] Better DrmInfo Resilience Armadillo to simply took the DRMInfo passed into it for granted without checking whether the content even needed a key to play. Exoplayer can raise an exception on its own and didn't need the DrmMediaSourceHelper to throw its own exceptions separately. --- .../playback/ExoPlaybackExceptionExt.kt | 5 +++ .../mediasource/DrmMediaSourceHelper.kt | 37 +++++++++++-------- RELEASE.md | 1 + 3 files changed, 27 insertions(+), 16 deletions(-) diff --git a/Armadillo/src/main/java/com/scribd/armadillo/playback/ExoPlaybackExceptionExt.kt b/Armadillo/src/main/java/com/scribd/armadillo/playback/ExoPlaybackExceptionExt.kt index ca9d88e..e606ee4 100644 --- a/Armadillo/src/main/java/com/scribd/armadillo/playback/ExoPlaybackExceptionExt.kt +++ b/Armadillo/src/main/java/com/scribd/armadillo/playback/ExoPlaybackExceptionExt.kt @@ -6,12 +6,14 @@ import com.google.android.exoplayer2.ExoPlaybackException.TYPE_RENDERER import com.google.android.exoplayer2.ExoPlaybackException.TYPE_SOURCE import com.google.android.exoplayer2.ParserException import com.google.android.exoplayer2.audio.AudioSink +import com.google.android.exoplayer2.drm.DrmSession.DrmSessionException import com.google.android.exoplayer2.drm.MediaDrmCallbackException import com.google.android.exoplayer2.upstream.DataSpec import com.google.android.exoplayer2.upstream.HttpDataSource import com.scribd.armadillo.error.ArmadilloException import com.scribd.armadillo.error.ArmadilloIOException import com.scribd.armadillo.error.ConnectivityException +import com.scribd.armadillo.error.DrmPlaybackException import com.scribd.armadillo.error.HttpResponseCodeException import com.scribd.armadillo.error.ParsingException import com.scribd.armadillo.error.RendererConfigurationException @@ -39,6 +41,9 @@ internal fun ExoPlaybackException.toArmadilloException(context: Context): Armadi HttpResponseCodeException(httpCause?.responseCode ?: 0, httpCause?.dataSpec?.uri.toString(), source, source.dataSpec.toAnalyticsMap(context)) } + is DrmSessionException -> { + DrmPlaybackException(cause = this) + } is UnknownHostException, is SocketTimeoutException -> ConnectivityException(source) diff --git a/Armadillo/src/main/java/com/scribd/armadillo/playback/mediasource/DrmMediaSourceHelper.kt b/Armadillo/src/main/java/com/scribd/armadillo/playback/mediasource/DrmMediaSourceHelper.kt index e43be2f..af043bb 100644 --- a/Armadillo/src/main/java/com/scribd/armadillo/playback/mediasource/DrmMediaSourceHelper.kt +++ b/Armadillo/src/main/java/com/scribd/armadillo/playback/mediasource/DrmMediaSourceHelper.kt @@ -31,23 +31,28 @@ internal class DrmMediaSourceHelperImpl @Inject constructor(private val secureSt MediaItem.Builder() .setUri(request.url) .apply { - // Apply DRM config if content is DRM-protected - request.drmInfo?.let { drmInfo -> - MediaItem.DrmConfiguration.Builder(drmInfo.drmType.toExoplayerConstant()) - .setLicenseUri(drmInfo.licenseServer) - .setLicenseRequestHeaders(drmInfo.drmHeaders) - .apply { - // If the content is a download content, use the saved offline DRM key id. - // This ID is needed to retrieve the local DRM license for content decryption. - if (isDownload) { - secureStorage.getDrmDownload(context = context, id = id, drmType = drmInfo.drmType)?.let { drmDownload -> - setKeySetId(drmDownload.drmKeyId) - } ?: throw DrmPlaybackException(IllegalStateException("No DRM key id saved for download content")) + try { + // Apply DRM config if content is DRM-protected + request.drmInfo?.let { drmInfo -> + MediaItem.DrmConfiguration.Builder(drmInfo.drmType.toExoplayerConstant()) + .setLicenseUri(drmInfo.licenseServer) + .setLicenseRequestHeaders(drmInfo.drmHeaders) + .apply { + // If the content is a download content, use the saved offline DRM key id. + // This ID is needed to retrieve the local DRM license for content decryption. + if (isDownload) { + secureStorage.getDrmDownload(context = context, id = id, drmType = drmInfo.drmType)?.let { drmDownload -> + setKeySetId(drmDownload.drmKeyId) + } ?: throw DrmPlaybackException(IllegalStateException("No DRM key id saved for download content")) + } } - } - .build() - }?.let { drmConfig -> - setDrmConfiguration(drmConfig) + .build() + }?.let { drmConfig -> + setDrmConfiguration(drmConfig) + } + } catch (ex: DrmPlaybackException) { + //attempt to load unencrypted, there's a chance the user supplied excessive DRMInfo. An exception will + // be raised elsewhere if this content can't be decrypted. } } .build() diff --git a/RELEASE.md b/RELEASE.md index 2e7d6ec..9f6332f 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -2,6 +2,7 @@ ## 1.6.8 - Fixes an app startup crash to EncryptedSharedPreference faults. +- Adds resilience to playing unencrypted content if it is optionally drm enabled. ## 1.6.7 - Adds additional data in audio player errors: HttpResponseCodeException, DownloadFailed