Fix crashes

This commit is contained in:
Koitharu
2024-03-23 15:59:22 +02:00
parent 559e546462
commit 0a1bc6716b
4 changed files with 37 additions and 5 deletions

View File

@@ -16,6 +16,7 @@ import org.koitharu.kotatsu.core.network.cookies.MutableCookieJar
import org.koitharu.kotatsu.core.prefs.SourceSettings import org.koitharu.kotatsu.core.prefs.SourceSettings
import org.koitharu.kotatsu.core.util.ext.configureForParser import org.koitharu.kotatsu.core.util.ext.configureForParser
import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug
import org.koitharu.kotatsu.core.util.ext.sanitizeHeaderValue
import org.koitharu.kotatsu.core.util.ext.toList import org.koitharu.kotatsu.core.util.ext.toList
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.config.MangaSourceConfig import org.koitharu.kotatsu.parsers.config.MangaSourceConfig
@@ -41,7 +42,7 @@ class MangaLoaderContextImpl @Inject constructor(
private val userAgentLazy = SuspendLazy { private val userAgentLazy = SuspendLazy {
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
obtainWebView().settings.userAgentString obtainWebView().settings.userAgentString
} }.sanitizeHeaderValue()
} }
@SuppressLint("SetJavaScriptEnabled") @SuppressLint("SetJavaScriptEnabled")

View File

@@ -3,9 +3,11 @@ package org.koitharu.kotatsu.core.prefs
import android.content.Context import android.content.Context
import android.content.SharedPreferences.OnSharedPreferenceChangeListener import android.content.SharedPreferences.OnSharedPreferenceChangeListener
import androidx.core.content.edit import androidx.core.content.edit
import okhttp3.internal.isSensitiveHeader
import org.koitharu.kotatsu.core.util.ext.getEnumValue import org.koitharu.kotatsu.core.util.ext.getEnumValue
import org.koitharu.kotatsu.core.util.ext.ifNullOrEmpty import org.koitharu.kotatsu.core.util.ext.ifNullOrEmpty
import org.koitharu.kotatsu.core.util.ext.putEnumValue import org.koitharu.kotatsu.core.util.ext.putEnumValue
import org.koitharu.kotatsu.core.util.ext.sanitizeHeaderValue
import org.koitharu.kotatsu.parsers.config.ConfigKey import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.config.MangaSourceConfig import org.koitharu.kotatsu.parsers.config.MangaSourceConfig
import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.model.MangaSource
@@ -25,7 +27,10 @@ class SourceSettings(context: Context, source: MangaSource) : MangaSourceConfig
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
override fun <T> get(key: ConfigKey<T>): T { override fun <T> get(key: ConfigKey<T>): T {
return when (key) { return when (key) {
is ConfigKey.UserAgent -> prefs.getString(key.key, key.defaultValue).ifNullOrEmpty { key.defaultValue } is ConfigKey.UserAgent -> prefs.getString(key.key, key.defaultValue)
.ifNullOrEmpty { key.defaultValue }
.sanitizeHeaderValue()
is ConfigKey.Domain -> prefs.getString(key.key, key.defaultValue).ifNullOrEmpty { key.defaultValue } is ConfigKey.Domain -> prefs.getString(key.key, key.defaultValue).ifNullOrEmpty { key.defaultValue }
is ConfigKey.ShowSuspiciousContent -> prefs.getBoolean(key.key, key.defaultValue) is ConfigKey.ShowSuspiciousContent -> prefs.getBoolean(key.key, key.defaultValue)
is ConfigKey.SplitByTranslations -> prefs.getBoolean(key.key, key.defaultValue) is ConfigKey.SplitByTranslations -> prefs.getBoolean(key.key, key.defaultValue)
@@ -36,7 +41,7 @@ class SourceSettings(context: Context, source: MangaSource) : MangaSourceConfig
when (key) { when (key) {
is ConfigKey.Domain -> putString(key.key, value as String?) is ConfigKey.Domain -> putString(key.key, value as String?)
is ConfigKey.ShowSuspiciousContent -> putBoolean(key.key, value as Boolean) is ConfigKey.ShowSuspiciousContent -> putBoolean(key.key, value as Boolean)
is ConfigKey.UserAgent -> putString(key.key, value as String?) is ConfigKey.UserAgent -> putString(key.key, (value as String?)?.sanitizeHeaderValue())
is ConfigKey.SplitByTranslations -> putBoolean(key.key, value as Boolean) is ConfigKey.SplitByTranslations -> putBoolean(key.key, value as Boolean)
} }
} }

View File

@@ -1,11 +1,13 @@
package org.koitharu.kotatsu.core.util.ext package org.koitharu.kotatsu.core.util.ext
import okhttp3.Cookie import okhttp3.Cookie
import okhttp3.Headers
import okhttp3.HttpUrl import okhttp3.HttpUrl
import okhttp3.MediaType.Companion.toMediaType import okhttp3.MediaType.Companion.toMediaType
import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.Response import okhttp3.Response
import okhttp3.internal.closeQuietly import okhttp3.internal.closeQuietly
import okhttp3.internal.isSensitiveHeader
import okio.IOException import okio.IOException
import org.json.JSONObject import org.json.JSONObject
import org.jsoup.HttpStatusException import org.jsoup.HttpStatusException
@@ -59,3 +61,16 @@ fun Cookie.newBuilder(): Cookie.Builder = Cookie.Builder().also { c ->
c.httpOnly() c.httpOnly()
} }
} }
fun String.sanitizeHeaderValue(): String {
return if (all(Char::isValidForHeaderValue)) {
this // fast path
} else {
filter(Char::isValidForHeaderValue)
}
}
private fun Char.isValidForHeaderValue(): Boolean {
// from okhttp3.Headers$Companion.checkValue
return this == '\t' || this in '\u0020'..'\u007e'
}

View File

@@ -13,13 +13,16 @@ import androidx.core.graphics.Insets
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams import androidx.core.view.updateLayoutParams
import androidx.core.view.updatePadding import androidx.core.view.updatePadding
import com.google.android.material.snackbar.Snackbar
import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.exceptions.resolve.SnackbarErrorObserver import org.koitharu.kotatsu.core.exceptions.resolve.SnackbarErrorObserver
import org.koitharu.kotatsu.core.ui.BaseActivity import org.koitharu.kotatsu.core.ui.BaseActivity
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
import org.koitharu.kotatsu.core.util.ext.observe import org.koitharu.kotatsu.core.util.ext.observe
import org.koitharu.kotatsu.core.util.ext.observeEvent import org.koitharu.kotatsu.core.util.ext.observeEvent
import org.koitharu.kotatsu.core.util.ext.tryLaunch
import org.koitharu.kotatsu.databinding.ActivityMangaDirectoriesBinding import org.koitharu.kotatsu.databinding.ActivityMangaDirectoriesBinding
import org.koitharu.kotatsu.settings.storage.DirectoryDiffCallback import org.koitharu.kotatsu.settings.storage.DirectoryDiffCallback
import org.koitharu.kotatsu.settings.storage.DirectoryModel import org.koitharu.kotatsu.settings.storage.DirectoryModel
@@ -42,7 +45,11 @@ class MangaDirectoriesActivity : BaseActivity<ActivityMangaDirectoriesBinding>()
) { ) {
if (it) { if (it) {
viewModel.updateList() viewModel.updateList()
pickFileTreeLauncher.launch(null) if (!pickFileTreeLauncher.tryLaunch(null)) {
Snackbar.make(
viewBinding.recyclerView, R.string.operation_not_supported, Snackbar.LENGTH_SHORT,
).show()
}
} }
} }
@@ -68,7 +75,11 @@ class MangaDirectoriesActivity : BaseActivity<ActivityMangaDirectoriesBinding>()
} }
override fun onClick(v: View?) { override fun onClick(v: View?) {
permissionRequestLauncher.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE) if (!permissionRequestLauncher.tryLaunch(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
Snackbar.make(
viewBinding.recyclerView, R.string.operation_not_supported, Snackbar.LENGTH_SHORT,
).show()
}
} }
override fun onWindowInsetsChanged(insets: Insets) { override fun onWindowInsetsChanged(insets: Insets) {