Feature/improve server config non privacy safe setting handling (#1794)

* Move the "group" arg at the second position after "protoNumber"

To make it consistent for all settings

* Improve server config non privacy safe setting handling

---------

Co-authored-by: Mitchell Syer <Syer10@users.noreply.github.com>
This commit is contained in:
schroda
2025-11-26 03:58:00 +01:00
committed by GitHub
parent aa8d27f679
commit 9d7f54be82
5 changed files with 182 additions and 40 deletions

View File

@@ -178,6 +178,23 @@ open class ConfigManager {
userConfigFile.writeText(newUserConfigDoc.render()) userConfigFile.writeText(newUserConfigDoc.render())
getUserConfig().entrySet().forEach { internalConfig = internalConfig.withValue(it.key, it.value) } getUserConfig().entrySet().forEach { internalConfig = internalConfig.withValue(it.key, it.value) }
} }
fun getRedactedConfig(nonPrivacySafeKeys: List<String>): Config {
val entries =
config.entrySet().associate { entry ->
val key = entry.key
val value =
if (nonPrivacySafeKeys.any { key.split(".").getOrNull(1) == it }) {
"[REDACTED]"
} else {
entry.value.unwrapped()
}
key to value
}
return ConfigFactory.parseMap(entries)
}
} }
object GlobalConfigManager : ConfigManager() object GlobalConfigManager : ConfigManager()

View File

@@ -85,6 +85,7 @@ class ServerConfig(
val ip: MutableStateFlow<String> by StringSetting( val ip: MutableStateFlow<String> by StringSetting(
protoNumber = 1, protoNumber = 1,
group = SettingGroup.NETWORK, group = SettingGroup.NETWORK,
privacySafe = true,
defaultValue = "0.0.0.0", defaultValue = "0.0.0.0",
pattern = "^((25[0-5]|(2[0-4]|1\\d|[1-9]|)\\d)\\.?\\b){4}$".toRegex(), pattern = "^((25[0-5]|(2[0-4]|1\\d|[1-9]|)\\d)\\.?\\b){4}$".toRegex(),
excludeFromBackup = true, excludeFromBackup = true,
@@ -93,6 +94,7 @@ class ServerConfig(
val port: MutableStateFlow<Int> by IntSetting( val port: MutableStateFlow<Int> by IntSetting(
protoNumber = 2, protoNumber = 2,
group = SettingGroup.NETWORK, group = SettingGroup.NETWORK,
privacySafe = true,
defaultValue = 4567, defaultValue = 4567,
min = 1, min = 1,
max = 65535, max = 65535,
@@ -102,12 +104,14 @@ class ServerConfig(
val socksProxyEnabled: MutableStateFlow<Boolean> by BooleanSetting( val socksProxyEnabled: MutableStateFlow<Boolean> by BooleanSetting(
protoNumber = 3, protoNumber = 3,
group = SettingGroup.PROXY, group = SettingGroup.PROXY,
privacySafe = true,
defaultValue = false, defaultValue = false,
) )
val socksProxyVersion: MutableStateFlow<Int> by IntSetting( val socksProxyVersion: MutableStateFlow<Int> by IntSetting(
protoNumber = 4, protoNumber = 4,
group = SettingGroup.PROXY, group = SettingGroup.PROXY,
privacySafe = true,
defaultValue = 5, defaultValue = 5,
min = 4, min = 4,
max = 5, max = 5,
@@ -116,18 +120,21 @@ class ServerConfig(
val socksProxyHost: MutableStateFlow<String> by StringSetting( val socksProxyHost: MutableStateFlow<String> by StringSetting(
protoNumber = 5, protoNumber = 5,
group = SettingGroup.PROXY, group = SettingGroup.PROXY,
privacySafe = true,
defaultValue = "", defaultValue = "",
) )
val socksProxyPort: MutableStateFlow<String> by StringSetting( val socksProxyPort: MutableStateFlow<String> by StringSetting(
protoNumber = 6, protoNumber = 6,
group = SettingGroup.PROXY, group = SettingGroup.PROXY,
privacySafe = true,
defaultValue = "", defaultValue = "",
) )
val socksProxyUsername: MutableStateFlow<String> by StringSetting( val socksProxyUsername: MutableStateFlow<String> by StringSetting(
protoNumber = 7, protoNumber = 7,
group = SettingGroup.PROXY, group = SettingGroup.PROXY,
privacySafe = false,
defaultValue = "", defaultValue = "",
excludeFromBackup = true, excludeFromBackup = true,
) )
@@ -135,6 +142,7 @@ class ServerConfig(
val socksProxyPassword: MutableStateFlow<String> by StringSetting( val socksProxyPassword: MutableStateFlow<String> by StringSetting(
protoNumber = 8, protoNumber = 8,
group = SettingGroup.PROXY, group = SettingGroup.PROXY,
privacySafe = false,
defaultValue = "", defaultValue = "",
excludeFromBackup = true, excludeFromBackup = true,
) )
@@ -142,6 +150,7 @@ class ServerConfig(
val webUIFlavor: MutableStateFlow<WebUIFlavor> by EnumSetting( val webUIFlavor: MutableStateFlow<WebUIFlavor> by EnumSetting(
protoNumber = 9, protoNumber = 9,
group = SettingGroup.WEB_UI, group = SettingGroup.WEB_UI,
privacySafe = true,
defaultValue = WebUIFlavor.WEBUI, defaultValue = WebUIFlavor.WEBUI,
enumClass = WebUIFlavor::class, enumClass = WebUIFlavor::class,
typeInfo = SettingsRegistry.PartialTypeInfo(imports = listOf("suwayomi.tachidesk.graphql.types.WebUIFlavor")), typeInfo = SettingsRegistry.PartialTypeInfo(imports = listOf("suwayomi.tachidesk.graphql.types.WebUIFlavor")),
@@ -150,6 +159,7 @@ class ServerConfig(
val initialOpenInBrowserEnabled: MutableStateFlow<Boolean> by BooleanSetting( val initialOpenInBrowserEnabled: MutableStateFlow<Boolean> by BooleanSetting(
protoNumber = 10, protoNumber = 10,
group = SettingGroup.WEB_UI, group = SettingGroup.WEB_UI,
privacySafe = true,
defaultValue = true, defaultValue = true,
description = "Open client on startup", description = "Open client on startup",
) )
@@ -157,6 +167,7 @@ class ServerConfig(
val webUIInterface: MutableStateFlow<WebUIInterface> by EnumSetting( val webUIInterface: MutableStateFlow<WebUIInterface> by EnumSetting(
protoNumber = 11, protoNumber = 11,
group = SettingGroup.WEB_UI, group = SettingGroup.WEB_UI,
privacySafe = true,
defaultValue = WebUIInterface.BROWSER, defaultValue = WebUIInterface.BROWSER,
enumClass = WebUIInterface::class, enumClass = WebUIInterface::class,
typeInfo = SettingsRegistry.PartialTypeInfo(imports = listOf("suwayomi.tachidesk.graphql.types.WebUIInterface")), typeInfo = SettingsRegistry.PartialTypeInfo(imports = listOf("suwayomi.tachidesk.graphql.types.WebUIInterface")),
@@ -165,6 +176,7 @@ class ServerConfig(
val electronPath: MutableStateFlow<String> by PathSetting( val electronPath: MutableStateFlow<String> by PathSetting(
protoNumber = 12, protoNumber = 12,
group = SettingGroup.WEB_UI, group = SettingGroup.WEB_UI,
privacySafe = true,
defaultValue = "", defaultValue = "",
mustExist = true, mustExist = true,
excludeFromBackup = true, excludeFromBackup = true,
@@ -173,6 +185,7 @@ class ServerConfig(
val webUIChannel: MutableStateFlow<WebUIChannel> by EnumSetting( val webUIChannel: MutableStateFlow<WebUIChannel> by EnumSetting(
protoNumber = 13, protoNumber = 13,
group = SettingGroup.WEB_UI, group = SettingGroup.WEB_UI,
privacySafe = true,
defaultValue = WebUIChannel.STABLE, defaultValue = WebUIChannel.STABLE,
enumClass = WebUIChannel::class, enumClass = WebUIChannel::class,
typeInfo = SettingsRegistry.PartialTypeInfo(imports = listOf("suwayomi.tachidesk.graphql.types.WebUIChannel")), typeInfo = SettingsRegistry.PartialTypeInfo(imports = listOf("suwayomi.tachidesk.graphql.types.WebUIChannel")),
@@ -181,6 +194,7 @@ class ServerConfig(
val webUIUpdateCheckInterval: MutableStateFlow<Double> by DisableableDoubleSetting( val webUIUpdateCheckInterval: MutableStateFlow<Double> by DisableableDoubleSetting(
protoNumber = 14, protoNumber = 14,
group = SettingGroup.WEB_UI, group = SettingGroup.WEB_UI,
privacySafe = true,
defaultValue = 23.hours.inWholeHours.toDouble(), defaultValue = 23.hours.inWholeHours.toDouble(),
min = 0.0, min = 0.0,
max = 23.0, max = 23.0,
@@ -189,13 +203,15 @@ class ServerConfig(
val downloadAsCbz: MutableStateFlow<Boolean> by BooleanSetting( val downloadAsCbz: MutableStateFlow<Boolean> by BooleanSetting(
protoNumber = 15, protoNumber = 15,
defaultValue = false,
group = SettingGroup.DOWNLOADER, group = SettingGroup.DOWNLOADER,
privacySafe = true,
defaultValue = false,
) )
val downloadsPath: MutableStateFlow<String> by PathSetting( val downloadsPath: MutableStateFlow<String> by PathSetting(
protoNumber = 16, protoNumber = 16,
group = SettingGroup.DOWNLOADER, group = SettingGroup.DOWNLOADER,
privacySafe = true,
defaultValue = "", defaultValue = "",
mustExist = true, mustExist = true,
excludeFromBackup = true, excludeFromBackup = true,
@@ -203,13 +219,15 @@ class ServerConfig(
val autoDownloadNewChapters: MutableStateFlow<Boolean> by BooleanSetting( val autoDownloadNewChapters: MutableStateFlow<Boolean> by BooleanSetting(
protoNumber = 17, protoNumber = 17,
defaultValue = false,
group = SettingGroup.DOWNLOADER, group = SettingGroup.DOWNLOADER,
privacySafe = true,
defaultValue = false,
) )
val excludeEntryWithUnreadChapters: MutableStateFlow<Boolean> by BooleanSetting( val excludeEntryWithUnreadChapters: MutableStateFlow<Boolean> by BooleanSetting(
protoNumber = 18, protoNumber = 18,
group = SettingGroup.DOWNLOADER, group = SettingGroup.DOWNLOADER,
privacySafe = true,
defaultValue = true, defaultValue = true,
description = "Exclude entries with unread chapters from auto-download", description = "Exclude entries with unread chapters from auto-download",
) )
@@ -217,8 +235,9 @@ class ServerConfig(
@Deprecated("Will get removed", replaceWith = ReplaceWith("autoDownloadNewChaptersLimit")) @Deprecated("Will get removed", replaceWith = ReplaceWith("autoDownloadNewChaptersLimit"))
val autoDownloadAheadLimit: MutableStateFlow<Int> by MigratedConfigValue( val autoDownloadAheadLimit: MutableStateFlow<Int> by MigratedConfigValue(
protoNumber = 19, protoNumber = 19,
defaultValue = 0,
group = SettingGroup.DOWNLOADER, group = SettingGroup.DOWNLOADER,
privacySafe = true,
defaultValue = 0,
deprecated = deprecated =
SettingsRegistry.SettingDeprecated( SettingsRegistry.SettingDeprecated(
replaceWith = "autoDownloadNewChaptersLimit", replaceWith = "autoDownloadNewChaptersLimit",
@@ -232,6 +251,7 @@ class ServerConfig(
val autoDownloadNewChaptersLimit: MutableStateFlow<Int> by DisableableIntSetting( val autoDownloadNewChaptersLimit: MutableStateFlow<Int> by DisableableIntSetting(
protoNumber = 20, protoNumber = 20,
group = SettingGroup.DOWNLOADER, group = SettingGroup.DOWNLOADER,
privacySafe = true,
defaultValue = 0, defaultValue = 0,
min = 0, min = 0,
description = "Maximum number of new chapters to auto-download", description = "Maximum number of new chapters to auto-download",
@@ -240,6 +260,7 @@ class ServerConfig(
val autoDownloadIgnoreReUploads: MutableStateFlow<Boolean> by BooleanSetting( val autoDownloadIgnoreReUploads: MutableStateFlow<Boolean> by BooleanSetting(
protoNumber = 21, protoNumber = 21,
group = SettingGroup.DOWNLOADER, group = SettingGroup.DOWNLOADER,
privacySafe = true,
defaultValue = false, defaultValue = false,
description = "Ignore re-uploaded chapters from auto-download", description = "Ignore re-uploaded chapters from auto-download",
) )
@@ -247,6 +268,7 @@ class ServerConfig(
val extensionRepos: MutableStateFlow<List<String>> by ListSetting<String>( val extensionRepos: MutableStateFlow<List<String>> by ListSetting<String>(
protoNumber = 22, protoNumber = 22,
group = SettingGroup.EXTENSION, group = SettingGroup.EXTENSION,
privacySafe = false,
defaultValue = emptyList(), defaultValue = emptyList(),
itemValidator = { url -> itemValidator = { url ->
if (url.matches(repoMatchRegex)) { if (url.matches(repoMatchRegex)) {
@@ -272,6 +294,7 @@ class ServerConfig(
val maxSourcesInParallel: MutableStateFlow<Int> by IntSetting( val maxSourcesInParallel: MutableStateFlow<Int> by IntSetting(
protoNumber = 23, protoNumber = 23,
group = SettingGroup.EXTENSION, group = SettingGroup.EXTENSION,
privacySafe = true,
defaultValue = 6, defaultValue = 6,
min = 1, min = 1,
max = 20, max = 20,
@@ -282,25 +305,29 @@ class ServerConfig(
val excludeUnreadChapters: MutableStateFlow<Boolean> by BooleanSetting( val excludeUnreadChapters: MutableStateFlow<Boolean> by BooleanSetting(
protoNumber = 24, protoNumber = 24,
defaultValue = true,
group = SettingGroup.LIBRARY_UPDATES, group = SettingGroup.LIBRARY_UPDATES,
privacySafe = true,
defaultValue = true,
) )
val excludeNotStarted: MutableStateFlow<Boolean> by BooleanSetting( val excludeNotStarted: MutableStateFlow<Boolean> by BooleanSetting(
protoNumber = 25, protoNumber = 25,
defaultValue = true,
group = SettingGroup.LIBRARY_UPDATES, group = SettingGroup.LIBRARY_UPDATES,
privacySafe = true,
defaultValue = true,
) )
val excludeCompleted: MutableStateFlow<Boolean> by BooleanSetting( val excludeCompleted: MutableStateFlow<Boolean> by BooleanSetting(
protoNumber = 26, protoNumber = 26,
defaultValue = true,
group = SettingGroup.LIBRARY_UPDATES, group = SettingGroup.LIBRARY_UPDATES,
privacySafe = true,
defaultValue = true,
) )
val globalUpdateInterval: MutableStateFlow<Double> by DisableableDoubleSetting( val globalUpdateInterval: MutableStateFlow<Double> by DisableableDoubleSetting(
protoNumber = 27, protoNumber = 27,
group = SettingGroup.LIBRARY_UPDATES, group = SettingGroup.LIBRARY_UPDATES,
privacySafe = true,
defaultValue = 12.hours.inWholeHours.toDouble(), defaultValue = 12.hours.inWholeHours.toDouble(),
min = 6.0, min = 6.0,
description = "Time in hours", description = "Time in hours",
@@ -309,6 +336,7 @@ class ServerConfig(
val updateMangas: MutableStateFlow<Boolean> by BooleanSetting( val updateMangas: MutableStateFlow<Boolean> by BooleanSetting(
protoNumber = 28, protoNumber = 28,
group = SettingGroup.LIBRARY_UPDATES, group = SettingGroup.LIBRARY_UPDATES,
privacySafe = true,
defaultValue = false, defaultValue = false,
description = "Update manga metadata and thumbnail along with the chapter list update during the library update.", description = "Update manga metadata and thumbnail along with the chapter list update during the library update.",
) )
@@ -316,8 +344,9 @@ class ServerConfig(
@Deprecated("Will get removed", replaceWith = ReplaceWith("authMode")) @Deprecated("Will get removed", replaceWith = ReplaceWith("authMode"))
val basicAuthEnabled: MutableStateFlow<Boolean> by MigratedConfigValue( val basicAuthEnabled: MutableStateFlow<Boolean> by MigratedConfigValue(
protoNumber = 29, protoNumber = 29,
defaultValue = false,
group = SettingGroup.AUTH, group = SettingGroup.AUTH,
privacySafe = true,
defaultValue = false,
deprecated = deprecated =
SettingsRegistry.SettingDeprecated( SettingsRegistry.SettingDeprecated(
replaceWith = "authMode", replaceWith = "authMode",
@@ -343,6 +372,7 @@ class ServerConfig(
val authUsername: MutableStateFlow<String> by StringSetting( val authUsername: MutableStateFlow<String> by StringSetting(
protoNumber = 30, protoNumber = 30,
group = SettingGroup.AUTH, group = SettingGroup.AUTH,
privacySafe = false,
defaultValue = "", defaultValue = "",
excludeFromBackup = true, excludeFromBackup = true,
) )
@@ -350,21 +380,24 @@ class ServerConfig(
val authPassword: MutableStateFlow<String> by StringSetting( val authPassword: MutableStateFlow<String> by StringSetting(
protoNumber = 31, protoNumber = 31,
group = SettingGroup.AUTH, group = SettingGroup.AUTH,
privacySafe = false,
defaultValue = "", defaultValue = "",
excludeFromBackup = true, excludeFromBackup = true,
) )
val debugLogsEnabled: MutableStateFlow<Boolean> by BooleanSetting( val debugLogsEnabled: MutableStateFlow<Boolean> by BooleanSetting(
protoNumber = 32, protoNumber = 32,
defaultValue = false,
group = SettingGroup.MISC, group = SettingGroup.MISC,
privacySafe = true,
defaultValue = false,
) )
@Deprecated("Removed - does not do anything") @Deprecated("Removed - does not do anything")
val gqlDebugLogsEnabled: MutableStateFlow<Boolean> by MigratedConfigValue( val gqlDebugLogsEnabled: MutableStateFlow<Boolean> by MigratedConfigValue(
protoNumber = 33, protoNumber = 33,
defaultValue = false,
group = SettingGroup.MISC, group = SettingGroup.MISC,
privacySafe = true,
defaultValue = false,
deprecated = deprecated =
SettingsRegistry.SettingDeprecated( SettingsRegistry.SettingDeprecated(
message = "Removed - does not do anything", message = "Removed - does not do anything",
@@ -373,13 +406,15 @@ class ServerConfig(
val systemTrayEnabled: MutableStateFlow<Boolean> by BooleanSetting( val systemTrayEnabled: MutableStateFlow<Boolean> by BooleanSetting(
protoNumber = 34, protoNumber = 34,
defaultValue = true,
group = SettingGroup.MISC, group = SettingGroup.MISC,
privacySafe = true,
defaultValue = true,
) )
val maxLogFiles: MutableStateFlow<Int> by IntSetting( val maxLogFiles: MutableStateFlow<Int> by IntSetting(
protoNumber = 35, protoNumber = 35,
group = SettingGroup.MISC, group = SettingGroup.MISC,
privacySafe = true,
defaultValue = 31, defaultValue = 31,
min = 0, min = 0,
description = "The max number of days to keep files before they get deleted", description = "The max number of days to keep files before they get deleted",
@@ -389,6 +424,7 @@ class ServerConfig(
val maxLogFileSize: MutableStateFlow<String> by StringSetting( val maxLogFileSize: MutableStateFlow<String> by StringSetting(
protoNumber = 36, protoNumber = 36,
group = SettingGroup.MISC, group = SettingGroup.MISC,
privacySafe = true,
defaultValue = "10mb", defaultValue = "10mb",
pattern = logbackSizePattern, pattern = logbackSizePattern,
description = "Maximum log file size - values: 1 (bytes), 1KB (kilobytes), 1MB (megabytes), 1GB (gigabytes)", description = "Maximum log file size - values: 1 (bytes), 1KB (kilobytes), 1MB (megabytes), 1GB (gigabytes)",
@@ -397,6 +433,7 @@ class ServerConfig(
val maxLogFolderSize: MutableStateFlow<String> by StringSetting( val maxLogFolderSize: MutableStateFlow<String> by StringSetting(
protoNumber = 37, protoNumber = 37,
group = SettingGroup.MISC, group = SettingGroup.MISC,
privacySafe = true,
defaultValue = "100mb", defaultValue = "100mb",
pattern = logbackSizePattern, pattern = logbackSizePattern,
description = "Maximum log folder size - values: 1 (bytes), 1KB (kilobytes), 1MB (megabytes), 1GB (gigabytes)", description = "Maximum log folder size - values: 1 (bytes), 1KB (kilobytes), 1MB (megabytes), 1GB (gigabytes)",
@@ -405,6 +442,7 @@ class ServerConfig(
val backupPath: MutableStateFlow<String> by PathSetting( val backupPath: MutableStateFlow<String> by PathSetting(
protoNumber = 38, protoNumber = 38,
group = SettingGroup.BACKUP, group = SettingGroup.BACKUP,
privacySafe = true,
defaultValue = "", defaultValue = "",
mustExist = true, mustExist = true,
excludeFromBackup = true, excludeFromBackup = true,
@@ -413,6 +451,7 @@ class ServerConfig(
val backupTime: MutableStateFlow<String> by StringSetting( val backupTime: MutableStateFlow<String> by StringSetting(
protoNumber = 39, protoNumber = 39,
group = SettingGroup.BACKUP, group = SettingGroup.BACKUP,
privacySafe = true,
defaultValue = "00:00", defaultValue = "00:00",
pattern = "^([0-1]?[0-9]|2[0-3]):[0-5][0-9]$".toRegex(), pattern = "^([0-1]?[0-9]|2[0-3]):[0-5][0-9]$".toRegex(),
description = "Daily backup time (HH:MM) ; range: [00:00, 23:59]", description = "Daily backup time (HH:MM) ; range: [00:00, 23:59]",
@@ -421,6 +460,7 @@ class ServerConfig(
val backupInterval: MutableStateFlow<Int> by DisableableIntSetting( val backupInterval: MutableStateFlow<Int> by DisableableIntSetting(
protoNumber = 40, protoNumber = 40,
group = SettingGroup.BACKUP, group = SettingGroup.BACKUP,
privacySafe = true,
defaultValue = 1, defaultValue = 1,
min = 0, min = 0,
description = "Time in days", description = "Time in days",
@@ -429,6 +469,7 @@ class ServerConfig(
val backupTTL: MutableStateFlow<Int> by DisableableIntSetting( val backupTTL: MutableStateFlow<Int> by DisableableIntSetting(
protoNumber = 41, protoNumber = 41,
group = SettingGroup.BACKUP, group = SettingGroup.BACKUP,
privacySafe = true,
defaultValue = 14.days.inWholeDays.toInt(), defaultValue = 14.days.inWholeDays.toInt(),
min = 0, min = 0,
description = "Backup retention in days", description = "Backup retention in days",
@@ -437,6 +478,7 @@ class ServerConfig(
val localSourcePath: MutableStateFlow<String> by PathSetting( val localSourcePath: MutableStateFlow<String> by PathSetting(
protoNumber = 42, protoNumber = 42,
group = SettingGroup.LOCAL_SOURCE, group = SettingGroup.LOCAL_SOURCE,
privacySafe = true,
defaultValue = "", defaultValue = "",
mustExist = true, mustExist = true,
excludeFromBackup = true, excludeFromBackup = true,
@@ -444,20 +486,23 @@ class ServerConfig(
val flareSolverrEnabled: MutableStateFlow<Boolean> by BooleanSetting( val flareSolverrEnabled: MutableStateFlow<Boolean> by BooleanSetting(
protoNumber = 43, protoNumber = 43,
defaultValue = false,
group = SettingGroup.CLOUDFLARE, group = SettingGroup.CLOUDFLARE,
privacySafe = true,
defaultValue = false,
excludeFromBackup = true, excludeFromBackup = true,
) )
val flareSolverrUrl: MutableStateFlow<String> by StringSetting( val flareSolverrUrl: MutableStateFlow<String> by StringSetting(
protoNumber = 44, protoNumber = 44,
group = SettingGroup.CLOUDFLARE, group = SettingGroup.CLOUDFLARE,
privacySafe = true,
defaultValue = "http://localhost:8191", defaultValue = "http://localhost:8191",
) )
val flareSolverrTimeout: MutableStateFlow<Int> by IntSetting( val flareSolverrTimeout: MutableStateFlow<Int> by IntSetting(
protoNumber = 45, protoNumber = 45,
group = SettingGroup.CLOUDFLARE, group = SettingGroup.CLOUDFLARE,
privacySafe = true,
defaultValue = 60.seconds.inWholeSeconds.toInt(), defaultValue = 60.seconds.inWholeSeconds.toInt(),
min = 0, min = 0,
description = "Time in seconds", description = "Time in seconds",
@@ -466,12 +511,14 @@ class ServerConfig(
val flareSolverrSessionName: MutableStateFlow<String> by StringSetting( val flareSolverrSessionName: MutableStateFlow<String> by StringSetting(
protoNumber = 46, protoNumber = 46,
group = SettingGroup.CLOUDFLARE, group = SettingGroup.CLOUDFLARE,
privacySafe = true,
defaultValue = "suwayomi", defaultValue = "suwayomi",
) )
val flareSolverrSessionTtl: MutableStateFlow<Int> by IntSetting( val flareSolverrSessionTtl: MutableStateFlow<Int> by IntSetting(
protoNumber = 47, protoNumber = 47,
group = SettingGroup.CLOUDFLARE, group = SettingGroup.CLOUDFLARE,
privacySafe = true,
defaultValue = 15.minutes.inWholeMinutes.toInt(), defaultValue = 15.minutes.inWholeMinutes.toInt(),
min = 0, min = 0,
description = "Time in minutes", description = "Time in minutes",
@@ -479,13 +526,15 @@ class ServerConfig(
val flareSolverrAsResponseFallback: MutableStateFlow<Boolean> by BooleanSetting( val flareSolverrAsResponseFallback: MutableStateFlow<Boolean> by BooleanSetting(
protoNumber = 48, protoNumber = 48,
defaultValue = false,
group = SettingGroup.CLOUDFLARE, group = SettingGroup.CLOUDFLARE,
privacySafe = true,
defaultValue = false,
) )
val opdsUseBinaryFileSizes: MutableStateFlow<Boolean> by BooleanSetting( val opdsUseBinaryFileSizes: MutableStateFlow<Boolean> by BooleanSetting(
protoNumber = 49, protoNumber = 49,
group = SettingGroup.OPDS, group = SettingGroup.OPDS,
privacySafe = true,
defaultValue = false, defaultValue = false,
description = "Display file size in binary (KiB, MiB, GiB) instead of decimal (KB, MB, GB)", description = "Display file size in binary (KiB, MiB, GiB) instead of decimal (KB, MB, GB)",
) )
@@ -493,6 +542,7 @@ class ServerConfig(
val opdsItemsPerPage: MutableStateFlow<Int> by IntSetting( val opdsItemsPerPage: MutableStateFlow<Int> by IntSetting(
protoNumber = 50, protoNumber = 50,
group = SettingGroup.OPDS, group = SettingGroup.OPDS,
privacySafe = true,
defaultValue = 100, defaultValue = 100,
min = 10, min = 10,
max = 5000, max = 5000,
@@ -500,31 +550,36 @@ class ServerConfig(
val opdsEnablePageReadProgress: MutableStateFlow<Boolean> by BooleanSetting( val opdsEnablePageReadProgress: MutableStateFlow<Boolean> by BooleanSetting(
protoNumber = 51, protoNumber = 51,
defaultValue = true,
group = SettingGroup.OPDS, group = SettingGroup.OPDS,
privacySafe = true,
defaultValue = true,
) )
val opdsMarkAsReadOnDownload: MutableStateFlow<Boolean> by BooleanSetting( val opdsMarkAsReadOnDownload: MutableStateFlow<Boolean> by BooleanSetting(
protoNumber = 52, protoNumber = 52,
defaultValue = false,
group = SettingGroup.OPDS, group = SettingGroup.OPDS,
privacySafe = true,
defaultValue = false,
) )
val opdsShowOnlyUnreadChapters: MutableStateFlow<Boolean> by BooleanSetting( val opdsShowOnlyUnreadChapters: MutableStateFlow<Boolean> by BooleanSetting(
protoNumber = 53, protoNumber = 53,
defaultValue = false,
group = SettingGroup.OPDS, group = SettingGroup.OPDS,
privacySafe = true,
defaultValue = false,
) )
val opdsShowOnlyDownloadedChapters: MutableStateFlow<Boolean> by BooleanSetting( val opdsShowOnlyDownloadedChapters: MutableStateFlow<Boolean> by BooleanSetting(
protoNumber = 54, protoNumber = 54,
defaultValue = false,
group = SettingGroup.OPDS, group = SettingGroup.OPDS,
privacySafe = true,
defaultValue = false,
) )
val opdsChapterSortOrder: MutableStateFlow<SortOrder> by EnumSetting( val opdsChapterSortOrder: MutableStateFlow<SortOrder> by EnumSetting(
protoNumber = 55, protoNumber = 55,
group = SettingGroup.OPDS, group = SettingGroup.OPDS,
privacySafe = true,
defaultValue = SortOrder.DESC, defaultValue = SortOrder.DESC,
enumClass = SortOrder::class, enumClass = SortOrder::class,
typeInfo = SettingsRegistry.PartialTypeInfo(imports = listOf("org.jetbrains.exposed.sql.SortOrder")), typeInfo = SettingsRegistry.PartialTypeInfo(imports = listOf("org.jetbrains.exposed.sql.SortOrder")),
@@ -533,6 +588,7 @@ class ServerConfig(
val authMode: MutableStateFlow<AuthMode> by EnumSetting( val authMode: MutableStateFlow<AuthMode> by EnumSetting(
protoNumber = 56, protoNumber = 56,
group = SettingGroup.AUTH, group = SettingGroup.AUTH,
privacySafe = true,
defaultValue = AuthMode.NONE, defaultValue = AuthMode.NONE,
enumClass = AuthMode::class, enumClass = AuthMode::class,
typeInfo = SettingsRegistry.PartialTypeInfo(imports = listOf("suwayomi.tachidesk.graphql.types.AuthMode")), typeInfo = SettingsRegistry.PartialTypeInfo(imports = listOf("suwayomi.tachidesk.graphql.types.AuthMode")),
@@ -541,8 +597,9 @@ class ServerConfig(
fun createDownloadConversionsMap(protoNumber: Int, key: String) = MapSetting<String, DownloadConversion>( fun createDownloadConversionsMap(protoNumber: Int, key: String) = MapSetting<String, DownloadConversion>(
protoNumber = protoNumber, protoNumber = protoNumber,
defaultValue = emptyMap(),
group = SettingGroup.DOWNLOADER, group = SettingGroup.DOWNLOADER,
privacySafe = false,
defaultValue = emptyMap(),
typeInfo = typeInfo =
SettingsRegistry.PartialTypeInfo( SettingsRegistry.PartialTypeInfo(
specificType = "List<SettingsDownloadConversionType>", specificType = "List<SettingsDownloadConversionType>",
@@ -627,12 +684,14 @@ class ServerConfig(
val jwtAudience: MutableStateFlow<String> by StringSetting( val jwtAudience: MutableStateFlow<String> by StringSetting(
protoNumber = 58, protoNumber = 58,
group = SettingGroup.AUTH, group = SettingGroup.AUTH,
privacySafe = true,
defaultValue = "suwayomi-server-api", defaultValue = "suwayomi-server-api",
) )
val koreaderSyncServerUrl: MutableStateFlow<String> by StringSetting( val koreaderSyncServerUrl: MutableStateFlow<String> by StringSetting(
protoNumber = 59, protoNumber = 59,
group = SettingGroup.KOREADER_SYNC, group = SettingGroup.KOREADER_SYNC,
privacySafe = true,
defaultValue = "https://sync.koreader.rocks/", defaultValue = "https://sync.koreader.rocks/",
description = "KOReader Sync Server URL. Public alternative: https://kosync.ak-team.com:3042/", description = "KOReader Sync Server URL. Public alternative: https://kosync.ak-team.com:3042/",
) )
@@ -641,6 +700,7 @@ class ServerConfig(
val koreaderSyncUsername: MutableStateFlow<String> by MigratedConfigValue( val koreaderSyncUsername: MutableStateFlow<String> by MigratedConfigValue(
protoNumber = 60, protoNumber = 60,
group = SettingGroup.KOREADER_SYNC, group = SettingGroup.KOREADER_SYNC,
privacySafe = false,
defaultValue = "", defaultValue = "",
deprecated = SettingsRegistry.SettingDeprecated( deprecated = SettingsRegistry.SettingDeprecated(
replaceWith = "MOVE TO PREFERENCES", replaceWith = "MOVE TO PREFERENCES",
@@ -658,6 +718,7 @@ class ServerConfig(
val koreaderSyncUserkey: MutableStateFlow<String> by MigratedConfigValue( val koreaderSyncUserkey: MutableStateFlow<String> by MigratedConfigValue(
protoNumber = 61, protoNumber = 61,
group = SettingGroup.KOREADER_SYNC, group = SettingGroup.KOREADER_SYNC,
privacySafe = false,
defaultValue = "", defaultValue = "",
deprecated = SettingsRegistry.SettingDeprecated( deprecated = SettingsRegistry.SettingDeprecated(
replaceWith = "MOVE TO PREFERENCES", replaceWith = "MOVE TO PREFERENCES",
@@ -675,6 +736,7 @@ class ServerConfig(
val koreaderSyncDeviceId: MutableStateFlow<String> by MigratedConfigValue( val koreaderSyncDeviceId: MutableStateFlow<String> by MigratedConfigValue(
protoNumber = 62, protoNumber = 62,
group = SettingGroup.KOREADER_SYNC, group = SettingGroup.KOREADER_SYNC,
privacySafe = true,
defaultValue = "", defaultValue = "",
deprecated = SettingsRegistry.SettingDeprecated( deprecated = SettingsRegistry.SettingDeprecated(
replaceWith = "MOVE TO PREFERENCES", replaceWith = "MOVE TO PREFERENCES",
@@ -691,6 +753,7 @@ class ServerConfig(
val koreaderSyncChecksumMethod: MutableStateFlow<KoreaderSyncChecksumMethod> by EnumSetting( val koreaderSyncChecksumMethod: MutableStateFlow<KoreaderSyncChecksumMethod> by EnumSetting(
protoNumber = 63, protoNumber = 63,
group = SettingGroup.KOREADER_SYNC, group = SettingGroup.KOREADER_SYNC,
privacySafe = true,
defaultValue = KoreaderSyncChecksumMethod.BINARY, defaultValue = KoreaderSyncChecksumMethod.BINARY,
enumClass = KoreaderSyncChecksumMethod::class, enumClass = KoreaderSyncChecksumMethod::class,
typeInfo = SettingsRegistry.PartialTypeInfo(imports = listOf("suwayomi.tachidesk.graphql.types.KoreaderSyncChecksumMethod")), typeInfo = SettingsRegistry.PartialTypeInfo(imports = listOf("suwayomi.tachidesk.graphql.types.KoreaderSyncChecksumMethod")),
@@ -700,8 +763,9 @@ class ServerConfig(
@Deprecated("Use koreaderSyncStrategyForward and koreaderSyncStrategyBackward instead") @Deprecated("Use koreaderSyncStrategyForward and koreaderSyncStrategyBackward instead")
val koreaderSyncStrategy: MutableStateFlow<KoreaderSyncLegacyStrategy> by MigratedConfigValue( val koreaderSyncStrategy: MutableStateFlow<KoreaderSyncLegacyStrategy> by MigratedConfigValue(
protoNumber = 64, protoNumber = 64,
defaultValue = KoreaderSyncLegacyStrategy.DISABLED,
group = SettingGroup.KOREADER_SYNC, group = SettingGroup.KOREADER_SYNC,
privacySafe = true,
defaultValue = KoreaderSyncLegacyStrategy.DISABLED,
typeInfo = typeInfo =
SettingsRegistry.PartialTypeInfo( SettingsRegistry.PartialTypeInfo(
imports = listOf("suwayomi.tachidesk.graphql.types.KoreaderSyncLegacyStrategy"), imports = listOf("suwayomi.tachidesk.graphql.types.KoreaderSyncLegacyStrategy"),
@@ -772,6 +836,7 @@ class ServerConfig(
val koreaderSyncPercentageTolerance: MutableStateFlow<Double> by DoubleSetting( val koreaderSyncPercentageTolerance: MutableStateFlow<Double> by DoubleSetting(
protoNumber = 65, protoNumber = 65,
group = SettingGroup.KOREADER_SYNC, group = SettingGroup.KOREADER_SYNC,
privacySafe = true,
defaultValue = 0.000000000000001, defaultValue = 0.000000000000001,
min = 0.000000000000001, min = 0.000000000000001,
max = 1.0, max = 1.0,
@@ -781,6 +846,7 @@ class ServerConfig(
val jwtTokenExpiry: MutableStateFlow<Duration> by DurationSetting( val jwtTokenExpiry: MutableStateFlow<Duration> by DurationSetting(
protoNumber = 66, protoNumber = 66,
group = SettingGroup.AUTH, group = SettingGroup.AUTH,
privacySafe = true,
defaultValue = 5.minutes, defaultValue = 5.minutes,
min = 0.seconds, min = 0.seconds,
) )
@@ -788,6 +854,7 @@ class ServerConfig(
val jwtRefreshExpiry: MutableStateFlow<Duration> by DurationSetting( val jwtRefreshExpiry: MutableStateFlow<Duration> by DurationSetting(
protoNumber = 67, protoNumber = 67,
group = SettingGroup.AUTH, group = SettingGroup.AUTH,
privacySafe = true,
defaultValue = 60.days, defaultValue = 60.days,
min = 0.seconds, min = 0.seconds,
) )
@@ -795,6 +862,7 @@ class ServerConfig(
val webUIEnabled: MutableStateFlow<Boolean> by BooleanSetting( val webUIEnabled: MutableStateFlow<Boolean> by BooleanSetting(
protoNumber = 68, protoNumber = 68,
group = SettingGroup.WEB_UI, group = SettingGroup.WEB_UI,
privacySafe = true,
defaultValue = true, defaultValue = true,
requiresRestart = true, requiresRestart = true,
) )
@@ -802,6 +870,7 @@ class ServerConfig(
val databaseType: MutableStateFlow<DatabaseType> by EnumSetting( val databaseType: MutableStateFlow<DatabaseType> by EnumSetting(
protoNumber = 69, protoNumber = 69,
group = SettingGroup.DATABASE, group = SettingGroup.DATABASE,
privacySafe = true,
defaultValue = DatabaseType.H2, defaultValue = DatabaseType.H2,
enumClass = DatabaseType::class, enumClass = DatabaseType::class,
typeInfo = SettingsRegistry.PartialTypeInfo(imports = listOf("suwayomi.tachidesk.graphql.types.DatabaseType")), typeInfo = SettingsRegistry.PartialTypeInfo(imports = listOf("suwayomi.tachidesk.graphql.types.DatabaseType")),
@@ -811,6 +880,7 @@ class ServerConfig(
val databaseUrl: MutableStateFlow<String> by StringSetting( val databaseUrl: MutableStateFlow<String> by StringSetting(
protoNumber = 70, protoNumber = 70,
group = SettingGroup.DATABASE, group = SettingGroup.DATABASE,
privacySafe = true,
defaultValue = "postgresql://localhost:5432/suwayomi", defaultValue = "postgresql://localhost:5432/suwayomi",
excludeFromBackup = true, excludeFromBackup = true,
) )
@@ -818,6 +888,7 @@ class ServerConfig(
val databaseUsername: MutableStateFlow<String> by StringSetting( val databaseUsername: MutableStateFlow<String> by StringSetting(
protoNumber = 71, protoNumber = 71,
group = SettingGroup.DATABASE, group = SettingGroup.DATABASE,
privacySafe = false,
defaultValue = "", defaultValue = "",
excludeFromBackup = true, excludeFromBackup = true,
) )
@@ -825,6 +896,7 @@ class ServerConfig(
val databasePassword: MutableStateFlow<String> by StringSetting( val databasePassword: MutableStateFlow<String> by StringSetting(
protoNumber = 72, protoNumber = 72,
group = SettingGroup.DATABASE, group = SettingGroup.DATABASE,
privacySafe = false,
defaultValue = "", defaultValue = "",
excludeFromBackup = true, excludeFromBackup = true,
) )
@@ -832,6 +904,7 @@ class ServerConfig(
val koreaderSyncStrategyForward: MutableStateFlow<KoreaderSyncConflictStrategy> by EnumSetting( val koreaderSyncStrategyForward: MutableStateFlow<KoreaderSyncConflictStrategy> by EnumSetting(
protoNumber = 73, protoNumber = 73,
group = SettingGroup.KOREADER_SYNC, group = SettingGroup.KOREADER_SYNC,
privacySafe = true,
defaultValue = KoreaderSyncConflictStrategy.PROMPT, defaultValue = KoreaderSyncConflictStrategy.PROMPT,
enumClass = KoreaderSyncConflictStrategy::class, enumClass = KoreaderSyncConflictStrategy::class,
typeInfo = SettingsRegistry.PartialTypeInfo(imports = listOf("suwayomi.tachidesk.graphql.types.KoreaderSyncConflictStrategy")), typeInfo = SettingsRegistry.PartialTypeInfo(imports = listOf("suwayomi.tachidesk.graphql.types.KoreaderSyncConflictStrategy")),
@@ -841,6 +914,7 @@ class ServerConfig(
val koreaderSyncStrategyBackward: MutableStateFlow<KoreaderSyncConflictStrategy> by EnumSetting( val koreaderSyncStrategyBackward: MutableStateFlow<KoreaderSyncConflictStrategy> by EnumSetting(
protoNumber = 74, protoNumber = 74,
group = SettingGroup.KOREADER_SYNC, group = SettingGroup.KOREADER_SYNC,
privacySafe = true,
defaultValue = KoreaderSyncConflictStrategy.DISABLED, defaultValue = KoreaderSyncConflictStrategy.DISABLED,
enumClass = KoreaderSyncConflictStrategy::class, enumClass = KoreaderSyncConflictStrategy::class,
typeInfo = SettingsRegistry.PartialTypeInfo(imports = listOf("suwayomi.tachidesk.graphql.types.KoreaderSyncConflictStrategy")), typeInfo = SettingsRegistry.PartialTypeInfo(imports = listOf("suwayomi.tachidesk.graphql.types.KoreaderSyncConflictStrategy")),
@@ -850,6 +924,7 @@ class ServerConfig(
val webUISubpath: MutableStateFlow<String> by StringSetting( val webUISubpath: MutableStateFlow<String> by StringSetting(
protoNumber = 75, protoNumber = 75,
group = SettingGroup.WEB_UI, group = SettingGroup.WEB_UI,
privacySafe = true,
defaultValue = "", defaultValue = "",
pattern = "^(/[a-zA-Z0-9._-]+)*$".toRegex(), pattern = "^(/[a-zA-Z0-9._-]+)*$".toRegex(),
description = "Serve WebUI under a subpath (e.g., /manga). Leave empty for root path. Must start with / if specified.", description = "Serve WebUI under a subpath (e.g., /manga). Leave empty for root path. Must start with / if specified.",
@@ -860,48 +935,56 @@ class ServerConfig(
val autoBackupIncludeManga: MutableStateFlow<Boolean> by BooleanSetting( val autoBackupIncludeManga: MutableStateFlow<Boolean> by BooleanSetting(
protoNumber = 76, protoNumber = 76,
group = SettingGroup.BACKUP, group = SettingGroup.BACKUP,
privacySafe = true,
defaultValue = BackupFlags.DEFAULT.includeManga, defaultValue = BackupFlags.DEFAULT.includeManga,
) )
val autoBackupIncludeCategories: MutableStateFlow<Boolean> by BooleanSetting( val autoBackupIncludeCategories: MutableStateFlow<Boolean> by BooleanSetting(
protoNumber = 77, protoNumber = 77,
group = SettingGroup.BACKUP, group = SettingGroup.BACKUP,
privacySafe = true,
defaultValue = BackupFlags.DEFAULT.includeCategories, defaultValue = BackupFlags.DEFAULT.includeCategories,
) )
val autoBackupIncludeChapters: MutableStateFlow<Boolean> by BooleanSetting( val autoBackupIncludeChapters: MutableStateFlow<Boolean> by BooleanSetting(
protoNumber = 78, protoNumber = 78,
group = SettingGroup.BACKUP, group = SettingGroup.BACKUP,
privacySafe = true,
defaultValue = BackupFlags.DEFAULT.includeChapters, defaultValue = BackupFlags.DEFAULT.includeChapters,
) )
val autoBackupIncludeTracking: MutableStateFlow<Boolean> by BooleanSetting( val autoBackupIncludeTracking: MutableStateFlow<Boolean> by BooleanSetting(
protoNumber = 79, protoNumber = 79,
group = SettingGroup.BACKUP, group = SettingGroup.BACKUP,
privacySafe = true,
defaultValue = BackupFlags.DEFAULT.includeTracking, defaultValue = BackupFlags.DEFAULT.includeTracking,
) )
val autoBackupIncludeHistory: MutableStateFlow<Boolean> by BooleanSetting( val autoBackupIncludeHistory: MutableStateFlow<Boolean> by BooleanSetting(
protoNumber = 80, protoNumber = 80,
group = SettingGroup.BACKUP, group = SettingGroup.BACKUP,
privacySafe = true,
defaultValue = BackupFlags.DEFAULT.includeHistory, defaultValue = BackupFlags.DEFAULT.includeHistory,
) )
val autoBackupIncludeClientData: MutableStateFlow<Boolean> by BooleanSetting( val autoBackupIncludeClientData: MutableStateFlow<Boolean> by BooleanSetting(
protoNumber = 81, protoNumber = 81,
group = SettingGroup.BACKUP, group = SettingGroup.BACKUP,
privacySafe = true,
defaultValue = BackupFlags.DEFAULT.includeClientData, defaultValue = BackupFlags.DEFAULT.includeClientData,
) )
val autoBackupIncludeServerSettings: MutableStateFlow<Boolean> by BooleanSetting( val autoBackupIncludeServerSettings: MutableStateFlow<Boolean> by BooleanSetting(
protoNumber = 82, protoNumber = 82,
group = SettingGroup.BACKUP, group = SettingGroup.BACKUP,
privacySafe = true,
defaultValue = BackupFlags.DEFAULT.includeServerSettings, defaultValue = BackupFlags.DEFAULT.includeServerSettings,
) )
val opdsCbzMimetype: MutableStateFlow<CbzMediaType> by EnumSetting( val opdsCbzMimetype: MutableStateFlow<CbzMediaType> by EnumSetting(
protoNumber = 83, protoNumber = 83,
group = SettingGroup.OPDS, group = SettingGroup.OPDS,
privacySafe = true,
defaultValue = CbzMediaType.MODERN, defaultValue = CbzMediaType.MODERN,
enumClass = CbzMediaType::class, enumClass = CbzMediaType::class,
typeInfo = SettingsRegistry.PartialTypeInfo(imports = listOf("suwayomi.tachidesk.graphql.types.CbzMediaType")), typeInfo = SettingsRegistry.PartialTypeInfo(imports = listOf("suwayomi.tachidesk.graphql.types.CbzMediaType")),
@@ -917,6 +1000,7 @@ class ServerConfig(
val useHikariConnectionPool: MutableStateFlow<Boolean> by BooleanSetting( val useHikariConnectionPool: MutableStateFlow<Boolean> by BooleanSetting(
protoNumber = 85, protoNumber = 85,
group = SettingGroup.DATABASE, group = SettingGroup.DATABASE,
privacySafe = true,
defaultValue = true, defaultValue = true,
excludeFromBackup = true, excludeFromBackup = true,
description = "Use Hikari Connection Pool to connect to the database.", description = "Use Hikari Connection Pool to connect to the database.",
@@ -933,8 +1017,9 @@ class ServerConfig(
@Deprecated("Removed - prefer authUsername", replaceWith = ReplaceWith("authUsername")) @Deprecated("Removed - prefer authUsername", replaceWith = ReplaceWith("authUsername"))
val basicAuthUsername: MutableStateFlow<String> by MigratedConfigValue( val basicAuthUsername: MutableStateFlow<String> by MigratedConfigValue(
protoNumber = 99991, protoNumber = 99991,
defaultValue = "",
group = SettingGroup.AUTH, group = SettingGroup.AUTH,
privacySafe = false,
defaultValue = "",
deprecated = deprecated =
SettingsRegistry.SettingDeprecated( SettingsRegistry.SettingDeprecated(
replaceWith = "authUsername", replaceWith = "authUsername",
@@ -948,8 +1033,9 @@ class ServerConfig(
@Deprecated("Removed - prefer authPassword", replaceWith = ReplaceWith("authPassword")) @Deprecated("Removed - prefer authPassword", replaceWith = ReplaceWith("authPassword"))
val basicAuthPassword: MutableStateFlow<String> by MigratedConfigValue( val basicAuthPassword: MutableStateFlow<String> by MigratedConfigValue(
protoNumber = 99992, protoNumber = 99992,
defaultValue = "",
group = SettingGroup.AUTH, group = SettingGroup.AUTH,
privacySafe = false,
defaultValue = "",
deprecated = deprecated =
SettingsRegistry.SettingDeprecated( SettingsRegistry.SettingDeprecated(
replaceWith = "authPassword", replaceWith = "authPassword",

View File

@@ -16,6 +16,14 @@ import kotlin.reflect.KClass
import kotlin.reflect.KProperty import kotlin.reflect.KProperty
import kotlin.time.Duration import kotlin.time.Duration
private fun maybeRedact(value: Any, privacySafe: Boolean): String {
return if (privacySafe) {
value.toString()
} else {
"[REDACTED]"
}
}
/** /**
* Base delegate for settings to read values from the config file with automatic setting registration and validation * Base delegate for settings to read values from the config file with automatic setting registration and validation
*/ */
@@ -30,6 +38,7 @@ open class SettingDelegate<T : Any>(
protected val deprecated: SettingsRegistry.SettingDeprecated? = null, protected val deprecated: SettingsRegistry.SettingDeprecated? = null,
protected val description: String? = null, protected val description: String? = null,
protected val excludeFromBackup: Boolean? = null, protected val excludeFromBackup: Boolean? = null,
val privacySafe: Boolean,
) { ) {
var flow: MutableStateFlow<T>? = null var flow: MutableStateFlow<T>? = null
lateinit var propertyName: String lateinit var propertyName: String
@@ -83,7 +92,8 @@ open class SettingDelegate<T : Any>(
defaultValueComment defaultValueComment
} }
}, },
excludeFromBackup = excludeFromBackup excludeFromBackup = excludeFromBackup,
privacySafe = privacySafe,
), ),
) )
@@ -145,6 +155,7 @@ class MigratedConfigValue<T : Any>(
private val deprecated: SettingsRegistry.SettingDeprecated, private val deprecated: SettingsRegistry.SettingDeprecated,
private val readMigrated: (() -> T) = { defaultValue }, private val readMigrated: (() -> T) = { defaultValue },
private val setMigrated: ((T) -> Unit) = {}, private val setMigrated: ((T) -> Unit) = {},
private val privacySafe: Boolean
) { ) {
var flow: MutableStateFlow<T>? = null var flow: MutableStateFlow<T>? = null
lateinit var propertyName: String lateinit var propertyName: String
@@ -174,6 +185,7 @@ class MigratedConfigValue<T : Any>(
deprecated = deprecated, deprecated = deprecated,
requiresRestart = requiresRestart ?: false, requiresRestart = requiresRestart ?: false,
excludeFromBackup = null, excludeFromBackup = null,
privacySafe = privacySafe,
), ),
) )
@@ -215,15 +227,16 @@ class StringSetting(
requiresRestart: Boolean? = null, requiresRestart: Boolean? = null,
description: String? = null, description: String? = null,
excludeFromBackup: Boolean? = null, excludeFromBackup: Boolean? = null,
privacySafe: Boolean,
) : SettingDelegate<String>( ) : SettingDelegate<String>(
protoNumber = protoNumber, protoNumber = protoNumber,
defaultValue = defaultValue, defaultValue = defaultValue,
validator = { value -> validator = { value ->
when { when {
pattern != null && !value.matches(pattern) -> pattern != null && !value.matches(pattern) ->
"Value must match pattern: ${pattern.pattern}" "Value (${maybeRedact(value, privacySafe)}) must match pattern: ${pattern.pattern}"
maxLength != null && value.length > maxLength -> maxLength != null && value.length > maxLength ->
"Value must not exceed $maxLength characters" "Value (${maybeRedact(value, privacySafe)}) must not exceed $maxLength characters"
else -> null else -> null
} }
}, },
@@ -239,6 +252,7 @@ class StringSetting(
requiresRestart = requiresRestart, requiresRestart = requiresRestart,
description = description, description = description,
excludeFromBackup = excludeFromBackup, excludeFromBackup = excludeFromBackup,
privacySafe = privacySafe,
) )
abstract class RangeSetting<T : Comparable<T>>( abstract class RangeSetting<T : Comparable<T>>(
@@ -254,14 +268,15 @@ abstract class RangeSetting<T : Comparable<T>>(
requiresRestart: Boolean? = null, requiresRestart: Boolean? = null,
description: String? = null, description: String? = null,
excludeFromBackup: Boolean? = null, excludeFromBackup: Boolean? = null,
privacySafe: Boolean,
) : SettingDelegate<T>( ) : SettingDelegate<T>(
protoNumber = protoNumber, protoNumber = protoNumber,
defaultValue = defaultValue, defaultValue = defaultValue,
validator = validator =
validator ?: { value -> validator ?: { value ->
when { when {
min != null && value < min -> "Value must be at least $min" min != null && value < min -> "Value (${maybeRedact(value, privacySafe)}) must be at least $min"
max != null && value > max -> "Value must not exceed $max" max != null && value > max -> "Value (${maybeRedact(value, privacySafe)}) must not exceed $max"
else -> null else -> null
} }
}, },
@@ -287,6 +302,7 @@ abstract class RangeSetting<T : Comparable<T>>(
} }
}, },
excludeFromBackup = excludeFromBackup, excludeFromBackup = excludeFromBackup,
privacySafe = privacySafe,
) )
class IntSetting( class IntSetting(
@@ -301,6 +317,7 @@ class IntSetting(
requiresRestart: Boolean? = null, requiresRestart: Boolean? = null,
description: String? = null, description: String? = null,
excludeFromBackup: Boolean? = null, excludeFromBackup: Boolean? = null,
privacySafe: Boolean,
) : RangeSetting<Int>( ) : RangeSetting<Int>(
protoNumber = protoNumber, protoNumber = protoNumber,
defaultValue = defaultValue, defaultValue = defaultValue,
@@ -313,6 +330,7 @@ class IntSetting(
requiresRestart = requiresRestart, requiresRestart = requiresRestart,
description = description, description = description,
excludeFromBackup = excludeFromBackup, excludeFromBackup = excludeFromBackup,
privacySafe = privacySafe,
) )
class DisableableIntSetting( class DisableableIntSetting(
@@ -325,6 +343,7 @@ class DisableableIntSetting(
requiresRestart: Boolean? = null, requiresRestart: Boolean? = null,
description: String? = null, description: String? = null,
excludeFromBackup: Boolean? = null, excludeFromBackup: Boolean? = null,
privacySafe: Boolean,
) : RangeSetting<Int>( ) : RangeSetting<Int>(
protoNumber = protoNumber, protoNumber = protoNumber,
defaultValue = defaultValue, defaultValue = defaultValue,
@@ -333,8 +352,8 @@ class DisableableIntSetting(
validator = { value -> validator = { value ->
when { when {
value == 0 -> null value == 0 -> null
min != null && value < min -> "Value must be 0.0 or at least $min" min != null && value < min -> "Value (${maybeRedact(value, privacySafe)}) must be 0.0 or at least $min"
max != null && value > max -> "Value must be 0.0 or not exceed $max" max != null && value > max -> "Value (${maybeRedact(value, privacySafe)}) must be 0.0 or not exceed $max"
else -> null else -> null
} }
}, },
@@ -360,6 +379,7 @@ class DisableableIntSetting(
} }
}, },
excludeFromBackup = excludeFromBackup, excludeFromBackup = excludeFromBackup,
privacySafe = privacySafe,
) )
class DoubleSetting( class DoubleSetting(
@@ -374,6 +394,7 @@ class DoubleSetting(
requiresRestart: Boolean? = null, requiresRestart: Boolean? = null,
description: String? = null, description: String? = null,
excludeFromBackup: Boolean? = null, excludeFromBackup: Boolean? = null,
privacySafe: Boolean,
) : RangeSetting<Double>( ) : RangeSetting<Double>(
protoNumber = protoNumber, protoNumber = protoNumber,
defaultValue = defaultValue, defaultValue = defaultValue,
@@ -386,6 +407,7 @@ class DoubleSetting(
requiresRestart = requiresRestart, requiresRestart = requiresRestart,
description = description, description = description,
excludeFromBackup = excludeFromBackup, excludeFromBackup = excludeFromBackup,
privacySafe = privacySafe,
) )
class DisableableDoubleSetting( class DisableableDoubleSetting(
@@ -398,6 +420,7 @@ class DisableableDoubleSetting(
requiresRestart: Boolean? = null, requiresRestart: Boolean? = null,
description: String? = null, description: String? = null,
excludeFromBackup: Boolean? = null, excludeFromBackup: Boolean? = null,
privacySafe: Boolean,
) : RangeSetting<Double>( ) : RangeSetting<Double>(
protoNumber = protoNumber, protoNumber = protoNumber,
defaultValue = defaultValue, defaultValue = defaultValue,
@@ -406,8 +429,8 @@ class DisableableDoubleSetting(
validator = { value -> validator = { value ->
when { when {
value == 0.0 -> null value == 0.0 -> null
min != null && value < min -> "Value must be 0.0 or be at least $min" min != null && value < min -> "Value (${maybeRedact(value, privacySafe)}) must be 0.0 or be at least $min"
max != null && value > max -> "Value must be 0.0 or not exceed $max" max != null && value > max -> "Value (${maybeRedact(value, privacySafe)}) must be 0.0 or not exceed $max"
else -> null else -> null
} }
}, },
@@ -433,6 +456,7 @@ class DisableableDoubleSetting(
} }
}, },
excludeFromBackup = excludeFromBackup, excludeFromBackup = excludeFromBackup,
privacySafe = privacySafe,
) )
class BooleanSetting( class BooleanSetting(
@@ -443,6 +467,7 @@ class BooleanSetting(
requiresRestart: Boolean? = null, requiresRestart: Boolean? = null,
description: String? = null, description: String? = null,
excludeFromBackup: Boolean? = null, excludeFromBackup: Boolean? = null,
privacySafe: Boolean,
) : SettingDelegate<Boolean>( ) : SettingDelegate<Boolean>(
protoNumber = protoNumber, protoNumber = protoNumber,
defaultValue = defaultValue, defaultValue = defaultValue,
@@ -452,6 +477,7 @@ class BooleanSetting(
requiresRestart = requiresRestart, requiresRestart = requiresRestart,
description = description, description = description,
excludeFromBackup = excludeFromBackup, excludeFromBackup = excludeFromBackup,
privacySafe = privacySafe,
) )
class PathSetting( class PathSetting(
@@ -463,12 +489,13 @@ class PathSetting(
requiresRestart: Boolean? = null, requiresRestart: Boolean? = null,
description: String? = null, description: String? = null,
excludeFromBackup: Boolean? = null, excludeFromBackup: Boolean? = null,
privacySafe: Boolean,
) : SettingDelegate<String>( ) : SettingDelegate<String>(
protoNumber = protoNumber, protoNumber = protoNumber,
defaultValue = defaultValue, defaultValue = defaultValue,
validator = { value -> validator = { value ->
if (mustExist && value.isNotEmpty() && !File(value).exists()) { if (mustExist && value.isNotEmpty() && !File(value).exists()) {
"Path does not exist: $value" "Path does not exist: ${maybeRedact(value, privacySafe)}"
} else { } else {
null null
} }
@@ -478,6 +505,7 @@ class PathSetting(
requiresRestart = requiresRestart, requiresRestart = requiresRestart,
description = description, description = description,
excludeFromBackup = excludeFromBackup, excludeFromBackup = excludeFromBackup,
privacySafe = privacySafe,
) )
class EnumSetting<T : Enum<T>>( class EnumSetting<T : Enum<T>>(
@@ -490,12 +518,13 @@ class EnumSetting<T : Enum<T>>(
requiresRestart: Boolean? = null, requiresRestart: Boolean? = null,
description: String? = null, description: String? = null,
excludeFromBackup: Boolean? = null, excludeFromBackup: Boolean? = null,
privacySafe: Boolean,
) : SettingDelegate<T>( ) : SettingDelegate<T>(
protoNumber = protoNumber, protoNumber = protoNumber,
defaultValue = defaultValue, defaultValue = defaultValue,
validator = { value -> validator = { value ->
if (!enumClass.java.isInstance(value)) { if (!enumClass.java.isInstance(value)) {
"Invalid enum value for ${enumClass.simpleName}" "Invalid enum value (${maybeRedact(value, privacySafe)}) for ${enumClass.simpleName}"
} else { } else {
null null
} }
@@ -515,6 +544,7 @@ class EnumSetting<T : Enum<T>>(
} }
}, },
excludeFromBackup = excludeFromBackup, excludeFromBackup = excludeFromBackup,
privacySafe = privacySafe,
) )
class DurationSetting( class DurationSetting(
@@ -529,6 +559,7 @@ class DurationSetting(
requiresRestart: Boolean? = null, requiresRestart: Boolean? = null,
description: String? = null, description: String? = null,
excludeFromBackup: Boolean? = null, excludeFromBackup: Boolean? = null,
privacySafe: Boolean,
) : RangeSetting<Duration>( ) : RangeSetting<Duration>(
protoNumber = protoNumber, protoNumber = protoNumber,
defaultValue = defaultValue, defaultValue = defaultValue,
@@ -545,6 +576,7 @@ class DurationSetting(
requiresRestart = requiresRestart, requiresRestart = requiresRestart,
description = description, description = description,
excludeFromBackup = excludeFromBackup, excludeFromBackup = excludeFromBackup,
privacySafe = privacySafe,
) )
class ListSetting<T>( class ListSetting<T>(
@@ -558,6 +590,7 @@ class ListSetting<T>(
requiresRestart: Boolean? = null, requiresRestart: Boolean? = null,
description: String? = null, description: String? = null,
excludeFromBackup: Boolean? = null, excludeFromBackup: Boolean? = null,
privacySafe: Boolean,
) : SettingDelegate<List<T>>( ) : SettingDelegate<List<T>>(
protoNumber = protoNumber, protoNumber = protoNumber,
defaultValue = defaultValue, defaultValue = defaultValue,
@@ -583,6 +616,7 @@ class ListSetting<T>(
requiresRestart = requiresRestart, requiresRestart = requiresRestart,
description = description, description = description,
excludeFromBackup = excludeFromBackup, excludeFromBackup = excludeFromBackup,
privacySafe = privacySafe,
) )
class MapSetting<K, V>( class MapSetting<K, V>(
@@ -595,6 +629,7 @@ class MapSetting<K, V>(
requiresRestart: Boolean? = null, requiresRestart: Boolean? = null,
description: String? = null, description: String? = null,
excludeFromBackup: Boolean? = null, excludeFromBackup: Boolean? = null,
privacySafe: Boolean,
) : SettingDelegate<Map<K, V>>( ) : SettingDelegate<Map<K, V>>(
protoNumber = protoNumber, protoNumber = protoNumber,
defaultValue = defaultValue, defaultValue = defaultValue,
@@ -605,4 +640,5 @@ class MapSetting<K, V>(
requiresRestart = requiresRestart, requiresRestart = requiresRestart,
description = description, description = description,
excludeFromBackup = excludeFromBackup, excludeFromBackup = excludeFromBackup,
privacySafe = privacySafe,
) )

View File

@@ -74,6 +74,7 @@ object SettingsRegistry {
val requiresRestart: Boolean, val requiresRestart: Boolean,
val description: String? = null, val description: String? = null,
val excludeFromBackup: Boolean? = null, val excludeFromBackup: Boolean? = null,
val privacySafe: Boolean
) )
private val settings = mutableMapOf<String, SettingMetadata>() private val settings = mutableMapOf<String, SettingMetadata>()

View File

@@ -272,13 +272,15 @@ fun applicationSetup() {
logger.debug { logger.debug {
"Loaded config:\n" + "Loaded config:\n" +
GlobalConfigManager.config GlobalConfigManager
.root() .getRedactedConfig(
SettingsRegistry
.getAll()
.filter { !it.value.privacySafe }
.keys
.toList(),
).root()
.render(ConfigRenderOptions.concise().setFormatted(true)) .render(ConfigRenderOptions.concise().setFormatted(true))
.replace(
Regex("(\".*(?i:username|password).*\"\\s:\\s)\".*\""),
"$1\"[REDACTED]\"",
)
} }
logger.debug { "Data Root directory is set to: ${applicationDirs.dataRoot}" } logger.debug { "Data Root directory is set to: ${applicationDirs.dataRoot}" }
@@ -409,9 +411,9 @@ fun applicationSetup() {
vargs[4] as Boolean, vargs[4] as Boolean,
) )
}.distinctUntilChanged(), }.distinctUntilChanged(),
{ (databaseType, databaseUrl, databaseUsername, _, hikariCp) -> { (databaseType, databaseUrl, _databaseUsername, _databasePassword, hikariCp) ->
logger.info { logger.info {
"Database changed - type=$databaseType url=$databaseUrl, username=$databaseUsername, password=[REDACTED], hikaricp=$hikariCp" "Database changed - type=$databaseType url=$databaseUrl, username=[REDACTED], password=[REDACTED], hikaricp=$hikariCp"
} }
databaseUp() databaseUp()
@@ -464,7 +466,7 @@ fun applicationSetup() {
}.distinctUntilChanged(), }.distinctUntilChanged(),
{ (proxyEnabled, proxyVersion, proxyHost, proxyPort, proxyUsername, proxyPassword) -> { (proxyEnabled, proxyVersion, proxyHost, proxyPort, proxyUsername, proxyPassword) ->
logger.info { logger.info {
"Socks Proxy changed - enabled=$proxyEnabled address=$proxyHost:$proxyPort , username=$proxyUsername, password=[REDACTED]" "Socks Proxy changed - enabled=$proxyEnabled address=$proxyHost:$proxyPort , username=[REDACTED], password=[REDACTED]"
} }
if (proxyEnabled) { if (proxyEnabled) {
System.setProperty("socksProxyHost", proxyHost) System.setProperty("socksProxyHost", proxyHost)