diff --git a/server/server-config/src/main/kotlin/suwayomi/tachidesk/server/ServerConfig.kt b/server/server-config/src/main/kotlin/suwayomi/tachidesk/server/ServerConfig.kt index 6c16cd70..6f94b4c5 100644 --- a/server/server-config/src/main/kotlin/suwayomi/tachidesk/server/ServerConfig.kt +++ b/server/server-config/src/main/kotlin/suwayomi/tachidesk/server/ServerConfig.kt @@ -688,12 +688,22 @@ class ServerConfig( defaultValue = "suwayomi-server-api", ) - val koreaderSyncServerUrl: MutableStateFlow by StringSetting( + @Deprecated("Moved to preference store. User is supposed to use a login/logout mutation") + val koreaderSyncServerUrl: MutableStateFlow by MigratedConfigValue( protoNumber = 59, group = SettingGroup.KOREADER_SYNC, privacySafe = true, defaultValue = "https://sync.koreader.rocks/", - description = "KOReader Sync Server URL. Public alternative: https://kosync.ak-team.com:3042/", + deprecated = SettingsRegistry.SettingDeprecated( + replaceWith = "MOVE TO PREFERENCES", + message = "Moved to preference store. User is supposed to use a login/logout mutation", + migrateConfig = { value, config -> + val koreaderPreferences = application.getSharedPreferences("koreader_sync", Context.MODE_PRIVATE) + koreaderPreferences.edit().putString("server_address", value.unwrapped() as? String).apply() + + config + } + ), ) @Deprecated("Moved to preference store. User is supposed to use a login/logout mutation") diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/KoreaderSyncMutation.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/KoreaderSyncMutation.kt index b8ceae3a..e1ae1e4c 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/KoreaderSyncMutation.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/KoreaderSyncMutation.kt @@ -19,6 +19,7 @@ import java.util.concurrent.CompletableFuture class KoreaderSyncMutation { data class ConnectKoSyncAccountInput( val clientMutationId: String? = null, + val serverAddress: String, val username: String, val password: String, ) @@ -26,7 +27,7 @@ class KoreaderSyncMutation { @RequireAuth fun connectKoSyncAccount(input: ConnectKoSyncAccountInput): CompletableFuture = future { - val (message, status) = KoreaderSyncService.connect(input.username, input.password) + val (message, status) = KoreaderSyncService.connect(input.serverAddress, input.username, input.password) KoSyncConnectPayload( clientMutationId = input.clientMutationId, @@ -45,7 +46,7 @@ class KoreaderSyncMutation { KoreaderSyncService.logout() LogoutKoSyncAccountPayload( clientMutationId = input.clientMutationId, - status = KoSyncStatusPayload(isLoggedIn = false, username = null), + status = KoSyncStatusPayload(isLoggedIn = false, serverAddress = null, username = null), ) } diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/KoreaderSyncPayloads.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/KoreaderSyncPayloads.kt index 98bd41e6..ee65c295 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/KoreaderSyncPayloads.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/KoreaderSyncPayloads.kt @@ -2,6 +2,7 @@ package suwayomi.tachidesk.graphql.types data class KoSyncStatusPayload( val isLoggedIn: Boolean, + val serverAddress: String?, val username: String?, ) diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/sync/KoreaderSyncService.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/sync/KoreaderSyncService.kt index c50e2848..cf9a03e4 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/sync/KoreaderSyncService.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/sync/KoreaderSyncService.kt @@ -34,6 +34,7 @@ import kotlin.math.abs object KoreaderSyncService { private val preferences = Injekt.get().getSharedPreferences("koreader_sync", Context.MODE_PRIVATE) + private const val SERVER_ADDRESS_KEY = "server_address" private const val USERNAME_KEY = "username" private const val USERKEY_KEY = "user_key" private const val DEVICE_ID_KEY = "client_id" @@ -179,6 +180,7 @@ object KoreaderSyncService { } private suspend fun register( + serverAddress: String, username: String, userkey: String, ): AuthResult { @@ -188,7 +190,7 @@ object KoreaderSyncService { put("password", userkey) } val request = - buildRequest("${serverConfig.koreaderSyncServerUrl.value.removeSuffix("/")}/users/create") { + buildRequest("${serverAddress.removeSuffix("/")}/users/create") { post(payload.toString().toRequestBody("application/json".toMediaType())) } @@ -216,11 +218,12 @@ object KoreaderSyncService { } private suspend fun authorize( + serverAddress: String, username: String, userkey: String, ): AuthResult { val request = - buildRequest("${serverConfig.koreaderSyncServerUrl.value.removeSuffix("/")}/users/auth") { + buildRequest("${serverAddress.removeSuffix("/")}/users/auth") { get() addHeader("x-auth-user", username) addHeader("x-auth-key", userkey) @@ -241,61 +244,88 @@ object KoreaderSyncService { } } - private fun getCredentials(): Pair { + private fun getCredentials(): Triple { + val serverAddress = preferences.getString(SERVER_ADDRESS_KEY, "https://sync.koreader.rocks/")!! val username = preferences.getString(USERNAME_KEY, "")!! val userkey = preferences.getString(USERKEY_KEY, "")!! - return Pair(username, userkey) + return Triple(serverAddress, username, userkey) } private fun setCredentials( + serverAddress: String, username: String, userkey: String, ) { preferences .edit() + .putString(SERVER_ADDRESS_KEY, serverAddress) .putString(USERNAME_KEY, username) .putString(USERKEY_KEY, userkey) .apply() } + private fun clearCredentials() { + preferences.edit().clear().apply() + } + suspend fun connect( + serverAddress: String, username: String, password: String, ): ConnectResult { val userkey = Hash.md5(password) - val authResult = authorize(username, userkey) + val authResult = authorize(serverAddress, username, userkey) if (authResult.success) { - setCredentials(username, userkey) - return ConnectResult("Login successful.", KoSyncStatusPayload(isLoggedIn = true, username = username)) + setCredentials(serverAddress, username, userkey) + return ConnectResult( + "Login successful.", + KoSyncStatusPayload(isLoggedIn = true, serverAddress = serverAddress, username = username), + ) } if (authResult.isUserNotFoundError) { logger.info { "[KOSYNC CONNECT] Authorization failed, attempting to register new user." } - val registerResult = register(username, userkey) + val registerResult = register(serverAddress, username, userkey) return if (registerResult.success) { - setCredentials(username, userkey) - ConnectResult("Registration successful.", KoSyncStatusPayload(isLoggedIn = true, username = username)) + setCredentials(serverAddress, username, userkey) + ConnectResult( + "Registration successful.", + KoSyncStatusPayload(isLoggedIn = true, serverAddress = serverAddress, username = username), + ) } else { - ConnectResult(registerResult.message ?: "Registration failed.", KoSyncStatusPayload(isLoggedIn = false, username = null)) + ConnectResult( + registerResult.message ?: "Registration failed.", + KoSyncStatusPayload(isLoggedIn = false, serverAddress = null, username = null), + ) } } - return ConnectResult(authResult.message ?: "Authentication failed.", KoSyncStatusPayload(isLoggedIn = false, username = null)) + return ConnectResult( + authResult.message ?: "Authentication failed.", + KoSyncStatusPayload(isLoggedIn = false, serverAddress = null, username = null), + ) } - suspend fun logout() { - setCredentials("", "") + fun logout() { + clearCredentials() } suspend fun getStatus(): KoSyncStatusPayload { - val (username, userkey) = getCredentials() + val (serverAddress, username, userkey) = getCredentials() + if (username.isBlank() || userkey.isBlank()) { - return KoSyncStatusPayload(isLoggedIn = false, username = null) + return KoSyncStatusPayload(isLoggedIn = false, serverAddress = null, username = null) + } + + val authResult = authorize(serverAddress, username, userkey) + + return if (authResult.success) { + KoSyncStatusPayload(isLoggedIn = true, serverAddress = serverAddress, username = username) + } else { + KoSyncStatusPayload(isLoggedIn = false, serverAddress = null, username = null) } - val authResult = authorize(username, userkey) - return KoSyncStatusPayload(isLoggedIn = authResult.success, username = if (authResult.success) username else null) } suspend fun pushProgress(chapterId: Int) { @@ -309,8 +339,8 @@ object KoreaderSyncService { return } - val (username, userkey) = getCredentials() - if (username.isBlank() || userkey.isBlank()) return + val (serverAddress, username, userkey) = getCredentials() + if (serverAddress.isBlank() || username.isBlank() || userkey.isBlank()) return val chapterHash = getOrGenerateChapterHash(chapterId) if (chapterHash.isNullOrBlank()) { @@ -350,7 +380,7 @@ object KoreaderSyncService { val requestBody = json.encodeToString(KoreaderProgressPayload.serializer(), payload) val request = - buildRequest("${serverConfig.koreaderSyncServerUrl.value.removeSuffix("/")}/syncs/progress") { + buildRequest("${serverAddress.removeSuffix("/")}/syncs/progress") { put(requestBody.toRequestBody("application/json".toMediaType())) addHeader("x-auth-user", username) addHeader("x-auth-key", userkey) @@ -383,8 +413,8 @@ object KoreaderSyncService { return null } - val (username, userkey) = getCredentials() - if (username.isBlank() || userkey.isBlank()) return null + val (serverAddress, username, userkey) = getCredentials() + if (serverAddress.isBlank() || username.isBlank() || userkey.isBlank()) return null val chapterHash = getOrGenerateChapterHash(chapterId) if (chapterHash.isNullOrBlank()) { @@ -394,7 +424,7 @@ object KoreaderSyncService { try { val request = - buildRequest("${serverConfig.koreaderSyncServerUrl.value.removeSuffix("/")}/syncs/progress/$chapterHash") { + buildRequest("${serverAddress.removeSuffix("/")}/syncs/progress/$chapterHash") { get() addHeader("x-auth-user", username) addHeader("x-auth-key", userkey) @@ -434,9 +464,7 @@ object KoreaderSyncService { } val localPercentage = - if (localProgress?.pageCount ?: 0 > - 0 - ) { + if ((localProgress?.pageCount ?: 0) > 0) { (localProgress!!.lastPageRead + 1).toFloat() / localProgress.pageCount } else { 0f