Don't include "app state" preferences in backups

(cherry picked from commit ce7bf396ebc0b85d0e857c55b27cb5eab2ad9d5b)

# Conflicts:
#	app/build.gradle.kts
This commit is contained in:
arkon 2023-10-29 12:24:02 -04:00 committed by Jobobby04
parent 23d683133b
commit 20e9ea7725
10 changed files with 195 additions and 42 deletions

View File

@ -5,6 +5,7 @@ import androidx.annotation.StringRes
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.util.system.isPreviewBuildType
import eu.kanade.tachiyomi.util.system.isReleaseBuildType
import tachiyomi.core.preference.Preference
import tachiyomi.core.preference.PreferenceStore
class BasePreferences(
@ -12,9 +13,12 @@ class BasePreferences(
private val preferenceStore: PreferenceStore,
) {
fun downloadedOnly() = preferenceStore.getBoolean("pref_downloaded_only", false)
fun downloadedOnly() = preferenceStore.getBoolean(
Preference.appStateKey("pref_downloaded_only"),
false,
)
fun incognitoMode() = preferenceStore.getBoolean("incognito_mode", false)
fun incognitoMode() = preferenceStore.getBoolean(Preference.appStateKey("incognito_mode"), false)
fun extensionInstaller() = ExtensionInstallerPreference(context, preferenceStore)

View File

@ -2,6 +2,7 @@ package eu.kanade.domain.source.service
import eu.kanade.domain.source.interactor.SetMigrateSorting
import eu.kanade.tachiyomi.util.system.LocaleHelper
import tachiyomi.core.preference.Preference
import tachiyomi.core.preference.PreferenceStore
import tachiyomi.core.preference.getEnum
import tachiyomi.domain.library.model.LibraryDisplayMode
@ -18,7 +19,10 @@ class SourcePreferences(
fun pinnedSources() = preferenceStore.getStringSet("pinned_catalogues", emptySet())
fun lastUsedSource() = preferenceStore.getLong("last_catalogue_source", -1)
fun lastUsedSource() = preferenceStore.getLong(
Preference.appStateKey("last_catalogue_source"),
-1,
)
fun showNsfwSource() = preferenceStore.getBoolean("show_nsfw_source", true)
@ -28,7 +32,7 @@ class SourcePreferences(
fun extensionUpdatesCount() = preferenceStore.getInt("ext_updates_count", 0)
fun trustedSignatures() = preferenceStore.getStringSet("trusted_signatures", emptySet())
fun trustedSignatures() = preferenceStore.getStringSet(Preference.appStateKey("trusted_signatures"), emptySet())
fun hideInLibraryItems() = preferenceStore.getBoolean("browse_hide_in_library_items", false)

View File

@ -378,17 +378,28 @@ object Migrations {
}
}
if (oldVersion < 107) {
preferenceStore.getAll()
.filter { it.key.startsWith("pref_mangasync_") || it.key.startsWith("track_token_") }
.forEach { (key, value) ->
if (value is String) {
preferenceStore
.getString(Preference.privateKey(key))
.set(value)
preferenceStore.getString(key).delete()
}
}
replacePreferences(
preferenceStore = preferenceStore,
filterPredicate = { it.key.startsWith("pref_mangasync_") || it.key.startsWith("track_token_") },
newKey = { Preference.privateKey(it) },
)
}
if (oldVersion < 108) {
val prefsToReplace = listOf(
"pref_download_only",
"incognito_mode",
"last_catalogue_source",
"trusted_signatures",
"last_app_closed",
"library_update_last_timestamp",
"library_unseen_updates_count",
"last_used_category",
)
replacePreferences(
preferenceStore = preferenceStore,
filterPredicate = { it.key in prefsToReplace },
newKey = { Preference.appStateKey(it) },
)
}
return true
}
@ -396,3 +407,41 @@ object Migrations {
return false
}
}
@Suppress("UNCHECKED_CAST")
private fun replacePreferences(
preferenceStore: PreferenceStore,
filterPredicate: (Map.Entry<String, Any?>) -> Boolean,
newKey: (String) -> String,
) {
preferenceStore.getAll()
.filter(filterPredicate)
.forEach { (key, value) ->
when (value) {
is Int -> {
preferenceStore.getInt(newKey(key)).set(value)
preferenceStore.getInt(key).delete()
}
is Long -> {
preferenceStore.getLong(newKey(key)).set(value)
preferenceStore.getLong(key).delete()
}
is Float -> {
preferenceStore.getFloat(newKey(key)).set(value)
preferenceStore.getFloat(key).delete()
}
is String -> {
preferenceStore.getString(newKey(key)).set(value)
preferenceStore.getString(key).delete()
}
is Boolean -> {
preferenceStore.getBoolean(newKey(key)).set(value)
preferenceStore.getBoolean(key).delete()
}
is Set<*> -> (value as? Set<String>)?.let {
preferenceStore.getStringSet(newKey(key)).set(value)
preferenceStore.getStringSet(key).delete()
}
}
}
}

View File

@ -306,7 +306,9 @@ class BackupCreator(
@Suppress("UNCHECKED_CAST")
private fun Map<String, *>.toBackupPreferences(): List<BackupPreference> {
return this.filterKeys { !Preference.isPrivate(it) }
return this.filterKeys {
!Preference.isPrivate(it) && !Preference.isAppState(it)
}
.mapNotNull { (key, value) ->
when (value) {
is Int -> BackupPreference(key, IntPreferenceValue(value))

View File

@ -587,6 +587,47 @@ object EXHMigrations {
preferenceStore.getString(key).delete()
}
}
val prefsToReplace = listOf(
"pref_download_only",
"incognito_mode",
"last_catalogue_source",
"trusted_signatures",
"last_app_closed",
"library_update_last_timestamp",
"library_unseen_updates_count",
"last_used_category",
"skip_pre_migration",
"eh_auto_update_stats",
)
replacePreferences(
preferenceStore = preferenceStore,
filterPredicate = { it.key in prefsToReplace },
newKey = { Preference.appStateKey(it) },
)
val privatePrefsToReplace = listOf(
"sql_password",
"encrypt_database",
"cbz_password",
"password_protect_downloads",
"eh_ipb_member_id",
"enable_exhentai",
"eh_ipb_member_id",
"eh_ipb_pass_hash",
"eh_igneous",
"eh_ehSettingsProfile",
"eh_exhSettingsProfile",
"eh_settingsKey",
"eh_sessionCookie",
"eh_hathPerksCookie"
)
replacePreferences(
preferenceStore = preferenceStore,
filterPredicate = { it.key in privatePrefsToReplace },
newKey = { Preference.privateKey(it) },
)
}
// if (oldVersion under 1) { } (1 is current release version)
@ -710,4 +751,43 @@ object EXHMigrations {
handler.await { ehQueries.migrateSource(newId, oldId) }
}
}
@Suppress("UNCHECKED_CAST")
private fun replacePreferences(
preferenceStore: PreferenceStore,
filterPredicate: (Map.Entry<String, Any?>) -> Boolean,
newKey: (String) -> String,
) {
preferenceStore.getAll()
.filter(filterPredicate)
.forEach { (key, value) ->
when (value) {
is Int -> {
preferenceStore.getInt(newKey(key)).set(value)
preferenceStore.getInt(key).delete()
}
is Long -> {
preferenceStore.getLong(newKey(key)).set(value)
preferenceStore.getLong(key).delete()
}
is Float -> {
preferenceStore.getFloat(newKey(key)).set(value)
preferenceStore.getFloat(key).delete()
}
is String -> {
preferenceStore.getString(newKey(key)).set(value)
preferenceStore.getString(key).delete()
}
is Boolean -> {
preferenceStore.getBoolean(newKey(key)).set(value)
preferenceStore.getBoolean(key).delete()
}
is Set<*> -> (value as? Set<String>)?.let {
preferenceStore.getStringSet(newKey(key)).set(value)
preferenceStore.getStringSet(key).delete()
}
}
}
}
}

View File

@ -1,6 +1,7 @@
package eu.kanade.tachiyomi.core.security
import eu.kanade.tachiyomi.core.R
import tachiyomi.core.preference.Preference
import tachiyomi.core.preference.PreferenceStore
import tachiyomi.core.preference.getEnum
@ -21,22 +22,25 @@ class SecurityPreferences(
fun authenticatorDays() = this.preferenceStore.getInt("biometric_days", 0x7F)
fun encryptDatabase() = this.preferenceStore.getBoolean("encrypt_database", false)
fun encryptDatabase() = this.preferenceStore.getBoolean(Preference.privateKey("encrypt_database"), false)
fun sqlPassword() = this.preferenceStore.getString("sql_password", "")
fun sqlPassword() = this.preferenceStore.getString(Preference.privateKey("sql_password"), "")
fun passwordProtectDownloads() = preferenceStore.getBoolean("password_protect_downloads", false)
fun passwordProtectDownloads() = preferenceStore.getBoolean(Preference.privateKey("password_protect_downloads"), false)
fun encryptionType() = this.preferenceStore.getEnum("encryption_type", EncryptionType.AES_256)
fun cbzPassword() = this.preferenceStore.getString("cbz_password", "")
fun cbzPassword() = this.preferenceStore.getString(Preference.privateKey("cbz_password"), "")
// SY <--
/**
* For app lock. Will be set when there is a pending timed lock.
* Otherwise this pref should be deleted.
*/
fun lastAppClosed() = preferenceStore.getLong("last_app_closed", 0)
fun lastAppClosed() = preferenceStore.getLong(
Preference.appStateKey("last_app_closed"),
0,
)
enum class SecureScreenMode(val titleResId: Int) {
ALWAYS(R.string.lock_always),

View File

@ -22,21 +22,29 @@ interface Preference<T> {
fun stateIn(scope: CoroutineScope): StateFlow<T>
val isPrivate: Boolean
get() = key().startsWith(PRIVATE_PREFIX)
companion object {
/**
* A preference that should not be exposed in places like backups.
* A preference that should not be exposed in places like backups without user consent.
*/
fun isPrivate(key: String): Boolean {
return key.startsWith(PRIVATE_PREFIX)
}
fun privateKey(key: String): String {
return "${PRIVATE_PREFIX}$key"
}
/**
* A preference used for internal app state that isn't really a user preference
* and therefore should not be inplaces like backips.
*/
fun isAppState(key: String): Boolean {
return key.startsWith(APP_STATE_PREFIX)
}
fun appStateKey(key: String): String {
return "${APP_STATE_PREFIX}$key"
}
private const val APP_STATE_PREFIX = "__APP_STATE_"
private const val PRIVATE_PREFIX = "__PRIVATE_"
}
}

View File

@ -1,5 +1,6 @@
package tachiyomi.domain
import tachiyomi.core.preference.Preference
import tachiyomi.core.preference.PreferenceStore
class UnsortedPreferences(
@ -18,13 +19,13 @@ class UnsortedPreferences(
fun useSourceWithMost() = preferenceStore.getBoolean("use_source_with_most", false)
fun skipPreMigration() = preferenceStore.getBoolean("skip_pre_migration", false)
fun skipPreMigration() = preferenceStore.getBoolean(Preference.appStateKey("skip_pre_migration"), false)
fun hideNotFoundMigration() = preferenceStore.getBoolean("hide_not_found_migration", false)
fun isHentaiEnabled() = preferenceStore.getBoolean("eh_is_hentai_enabled", true)
fun enableExhentai() = preferenceStore.getBoolean("enable_exhentai", false)
fun enableExhentai() = preferenceStore.getBoolean(Preference.privateKey("enable_exhentai"), false)
fun imageQuality() = preferenceStore.getString("ehentai_quality", "auto")
@ -39,15 +40,15 @@ class UnsortedPreferences(
fun ehTagWatchingValue() = preferenceStore.getInt("eh_tag_watching_value", 0)
// EH Cookies
fun memberIdVal() = preferenceStore.getString("eh_ipb_member_id", "")
fun memberIdVal() = preferenceStore.getString(Preference.privateKey("eh_ipb_member_id"), "")
fun passHashVal() = preferenceStore.getString("eh_ipb_pass_hash", "")
fun igneousVal() = preferenceStore.getString("eh_igneous", "")
fun ehSettingsProfile() = preferenceStore.getInt("eh_ehSettingsProfile", -1)
fun exhSettingsProfile() = preferenceStore.getInt("eh_exhSettingsProfile", -1)
fun exhSettingsKey() = preferenceStore.getString("eh_settingsKey", "")
fun exhSessionCookie() = preferenceStore.getString("eh_sessionCookie", "")
fun exhHathPerksCookies() = preferenceStore.getString("eh_hathPerksCookie", "")
fun passHashVal() = preferenceStore.getString(Preference.privateKey("eh_ipb_pass_hash"), "")
fun igneousVal() = preferenceStore.getString(Preference.privateKey("eh_igneous"), "")
fun ehSettingsProfile() = preferenceStore.getInt(Preference.privateKey("eh_ehSettingsProfile"), -1)
fun exhSettingsProfile() = preferenceStore.getInt(Preference.privateKey("eh_exhSettingsProfile"), -1)
fun exhSettingsKey() = preferenceStore.getString(Preference.privateKey("eh_settingsKey"), "")
fun exhSessionCookie() = preferenceStore.getString(Preference.privateKey("eh_sessionCookie"), "")
fun exhHathPerksCookies() = preferenceStore.getString(Preference.privateKey("eh_hathPerksCookie"), "")
fun exhShowSyncIntro() = preferenceStore.getBoolean("eh_show_sync_intro", true)
@ -63,7 +64,7 @@ class UnsortedPreferences(
fun exhAutoUpdateRequirements() = preferenceStore.getStringSet("eh_auto_update_restrictions", emptySet())
fun exhAutoUpdateStats() = preferenceStore.getString("eh_auto_update_stats", "")
fun exhAutoUpdateStats() = preferenceStore.getString(Preference.appStateKey("eh_auto_update_stats"), "")
fun exhWatchedListDefaultState() = preferenceStore.getBoolean("eh_watched_list_default_state", false)

View File

@ -1,5 +1,6 @@
package tachiyomi.domain.backup.service
import tachiyomi.core.preference.Preference
import tachiyomi.core.preference.PreferenceStore
import tachiyomi.core.provider.FolderProvider
@ -14,6 +15,5 @@ class BackupPreferences(
fun backupInterval() = preferenceStore.getInt("backup_interval", 12)
// TODO: move this and other "app state" preferences elsewhere and exclude from backups
fun lastAutoBackupTimestamp() = preferenceStore.getLong("__APP_STATE_last_auto_backup_timestamp", 0L)
fun lastAutoBackupTimestamp() = preferenceStore.getLong(Preference.appStateKey("last_auto_backup_timestamp"), 0L)
}

View File

@ -1,5 +1,6 @@
package tachiyomi.domain.library.service
import tachiyomi.core.preference.Preference
import tachiyomi.core.preference.PreferenceStore
import tachiyomi.core.preference.TriState
import tachiyomi.core.preference.getEnum
@ -31,7 +32,7 @@ class LibraryPreferences(
fun landscapeColumns() = preferenceStore.getInt("pref_library_columns_landscape_key", 0)
fun lastUpdatedTimestamp() = preferenceStore.getLong("library_update_last_timestamp", 0L)
fun lastUpdatedTimestamp() = preferenceStore.getLong(Preference.appStateKey("library_update_last_timestamp"), 0L)
fun autoUpdateInterval() = preferenceStore.getInt("pref_library_update_interval_key", 0)
fun autoUpdateDeviceRestrictions() = preferenceStore.getStringSet(
@ -99,7 +100,7 @@ class LibraryPreferences(
fun languageBadge() = preferenceStore.getBoolean("display_language_badge", false)
fun newShowUpdatesCount() = preferenceStore.getBoolean("library_show_updates_count", true)
fun newUpdatesCount() = preferenceStore.getInt("library_unseen_updates_count", 0)
fun newUpdatesCount() = preferenceStore.getInt(Preference.appStateKey("library_unseen_updates_count"), 0)
// endregion
@ -107,7 +108,7 @@ class LibraryPreferences(
fun defaultCategory() = preferenceStore.getInt("default_category", -1)
fun lastUsedCategory() = preferenceStore.getInt("last_used_category", 0)
fun lastUsedCategory() = preferenceStore.getInt(Preference.appStateKey("last_used_category"), 0)
fun categoryTabs() = preferenceStore.getBoolean("display_category_tabs", true)