Fix crashes
This commit is contained in:
@@ -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")
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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'
|
||||||
|
}
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
Reference in New Issue
Block a user