Skip to content

Commit

Permalink
fix: CORS issue with JS loading
Browse files Browse the repository at this point in the history
  • Loading branch information
BrayanDSO committed May 4, 2024
1 parent 0f795ce commit 4738df0
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -993,6 +993,7 @@ abstract class AbstractFlashcardViewer :
}

protected open fun createWebView(): WebView {
val resourceHandler = ViewerResourceHandler(this)
val webView: WebView = MyWebView(this).apply {
scrollBarStyle = View.SCROLLBARS_OUTSIDE_OVERLAY
with(settings) {
Expand All @@ -1010,7 +1011,7 @@ abstract class AbstractFlashcardViewer :
isScrollbarFadingEnabled = true
// Set transparent color to prevent flashing white when night mode enabled
setBackgroundColor(Color.argb(1, 0, 0, 0))
CardViewerWebClient(this@AbstractFlashcardViewer).apply {
CardViewerWebClient(resourceHandler, this@AbstractFlashcardViewer).apply {
webViewClient = this
this@AbstractFlashcardViewer.webViewClient = this
}
Expand Down Expand Up @@ -2233,6 +2234,7 @@ abstract class AbstractFlashcardViewer :
}

inner class CardViewerWebClient internal constructor(
private val resourceHandler: ViewerResourceHandler,
private val onPageFinishedCallback: OnPageFinishedCallback? = null
) : WebViewClient(), JavascriptEvaluator {
private var pageFinishedFired = true
Expand Down Expand Up @@ -2266,6 +2268,7 @@ abstract class AbstractFlashcardViewer :
if (url.toString().startsWith("file://")) {
url.path?.let { path -> migrationService?.migrateFileImmediately(File(path)) }
}
resourceHandler.shouldInterceptRequest(request)?.let { return it }
return null
}

Expand Down
54 changes: 54 additions & 0 deletions AnkiDroid/src/main/java/com/ichi2/anki/ViewerResourceHandler.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright (c) 2024 Brayan Oliveira <[email protected]>
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.ichi2.anki

import android.content.Context
import android.webkit.WebResourceRequest
import android.webkit.WebResourceResponse
import androidx.core.net.toFile
import com.ichi2.utils.AssetHelper.guessMimeType
import timber.log.Timber
import java.io.FileInputStream

class ViewerResourceHandler(context: Context) {
private val mediaDir = CollectionHelper.getMediaDirectory(context).path

/**
* Loads resources from `collection.media` when requested by JS scripts.
*
* Differently from common media requests, scripts' requests have an `Origin` header
* and are susceptible to CORS policy, so `Access-Control-Allow-Origin` is necessary.
*/
fun shouldInterceptRequest(request: WebResourceRequest): WebResourceResponse? {
val url = request.url
if (request.method != "GET" || url.scheme != "file" || "Origin" !in request.requestHeaders) {
return null
}
try {
val file = url.toFile()
if (file.parent != mediaDir || !file.exists()) {
return null
}
val inputStream = FileInputStream(file)
return WebResourceResponse(guessMimeType(file.path), null, inputStream).apply {
responseHeaders = mapOf("Access-Control-Allow-Origin" to "*")
}
} catch (e: Exception) {
Timber.d("File couldn't be loaded")
return null
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import android.webkit.CookieManager
import android.webkit.WebChromeClient
import android.webkit.WebResourceError
import android.webkit.WebResourceRequest
import android.webkit.WebResourceResponse
import android.webkit.WebView
import android.webkit.WebViewClient
import android.widget.FrameLayout
Expand All @@ -37,6 +38,7 @@ import androidx.lifecycle.flowWithLifecycle
import androidx.lifecycle.lifecycleScope
import com.ichi2.anki.CollectionHelper
import com.ichi2.anki.R
import com.ichi2.anki.ViewerResourceHandler
import com.ichi2.anki.dialogs.TtsVoicesDialogFragment
import com.ichi2.anki.localizedErrorMessage
import com.ichi2.anki.snackbar.showSnackbar
Expand Down Expand Up @@ -121,7 +123,15 @@ abstract class CardViewerFragment(@LayoutRes layout: Int) : Fragment(layout) {
}

private fun onCreateWebViewClient(savedInstanceState: Bundle?): WebViewClient {
val resourceHandler = ViewerResourceHandler(requireContext())
return object : WebViewClient() {
override fun shouldInterceptRequest(
view: WebView?,
request: WebResourceRequest
): WebResourceResponse? {
return resourceHandler.shouldInterceptRequest(request)
}

override fun onPageFinished(view: WebView?, url: String?) {
viewModel.onPageFinished(isAfterRecreation = savedInstanceState != null)
}
Expand Down

0 comments on commit 4738df0

Please sign in to comment.