diff --git a/app/src/androidTest/java/com/owncloud/android/ui/dialog/DialogFragmentIT.kt b/app/src/androidTest/java/com/owncloud/android/ui/dialog/DialogFragmentIT.kt index 9112027bde61..1b232d3aa756 100644 --- a/app/src/androidTest/java/com/owncloud/android/ui/dialog/DialogFragmentIT.kt +++ b/app/src/androidTest/java/com/owncloud/android/ui/dialog/DialogFragmentIT.kt @@ -30,7 +30,6 @@ import androidx.test.espresso.matcher.ViewMatchers.isRoot import androidx.test.rule.GrantPermissionRule import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.gson.Gson -import com.google.gson.reflect.TypeToken import com.nextcloud.android.common.ui.color.ColorUtil import com.nextcloud.android.lib.resources.profile.Action import com.nextcloud.android.lib.resources.profile.HoverCard @@ -72,6 +71,7 @@ import com.owncloud.android.utils.theme.CapabilityUtils import com.owncloud.android.utils.theme.ViewThemeUtils import io.mockk.mockk import org.junit.After +import org.junit.Assert.assertEquals import org.junit.Assert.fail import org.junit.Rule import org.junit.Test @@ -717,22 +717,14 @@ class DialogFragmentIT : AbstractIT() { } @Test - fun testGson() { - val t = ArrayList().apply { - add(EnforcedServer("name", "url")) - add(EnforcedServer("name2", "url1")) - } - - val s = Gson().toJson(t) - val t2 = Gson().fromJson>( - s, - object : TypeToken?>() { - }.type + fun testEnforcedServerParsing() { + val expected = listOf( + EnforcedServer("name", "url"), + EnforcedServer("name2", "url1") ) - val temp = ArrayList() - for (p in t2) { - temp.add(p.name) - } + val parsed = EnforcedServer.fromJson("""[{"name":"name","url":"url"},{"name":"name2","url":"url1"}]""") + + assertEquals(expected, parsed) } } diff --git a/app/src/main/java/com/owncloud/android/authentication/AuthenticatorActivity.java b/app/src/main/java/com/owncloud/android/authentication/AuthenticatorActivity.java index dd720ccc985f..44c426bd2e72 100644 --- a/app/src/main/java/com/owncloud/android/authentication/AuthenticatorActivity.java +++ b/app/src/main/java/com/owncloud/android/authentication/AuthenticatorActivity.java @@ -51,7 +51,6 @@ import com.google.gson.Gson; import com.google.gson.JsonObject; import com.google.gson.JsonParser; -import com.google.gson.reflect.TypeToken; import com.nextcloud.android.common.ui.color.ColorUtil; import com.nextcloud.android.common.ui.theme.utils.ColorRole; import com.nextcloud.client.account.User; @@ -110,6 +109,7 @@ import java.net.URLDecoder; import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Objects; @@ -362,12 +362,9 @@ private void showEnforcedServers() { servers.add(""); adapter.add(getString(R.string.please_select_a_server)); - ArrayList t = new Gson().fromJson(getString(R.string.enforce_servers), - new TypeToken>() { - } - .getType()); + List enforcedServers = EnforcedServer.fromJson(getString(R.string.enforce_servers)); - for (EnforcedServer e : t) { + for (EnforcedServer e : enforcedServers) { adapter.add(e.getName()); servers.add(e.getUrl()); } @@ -681,10 +678,7 @@ private boolean checkAllowedServers(@NonNull String server) { String enforcedServerList = getString(R.string.enforce_servers); if (!enforcedServerList.isEmpty()) { - ArrayList enforcedServers = new Gson().fromJson(enforcedServerList, - new TypeToken>() { - } - .getType()); + List enforcedServers = EnforcedServer.fromJson(enforcedServerList); for (EnforcedServer enforcedServer : enforcedServers) { if (enforcedServer.getUrl().startsWith(server)) { diff --git a/app/src/main/java/com/owncloud/android/authentication/EnforcedServer.kt b/app/src/main/java/com/owncloud/android/authentication/EnforcedServer.kt index b9483d2112c6..c035816f294f 100644 --- a/app/src/main/java/com/owncloud/android/authentication/EnforcedServer.kt +++ b/app/src/main/java/com/owncloud/android/authentication/EnforcedServer.kt @@ -1,10 +1,31 @@ /* * Nextcloud - Android Client * + * SPDX-FileCopyrightText: 2026 Alper Ozturk * SPDX-FileCopyrightText: 2024 Tobias Kaminsky * SPDX-License-Identifier: AGPL-3.0-or-later */ package com.owncloud.android.authentication -data class EnforcedServer(val name: String, val url: String) +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.Json + +@Serializable +data class EnforcedServer(val name: String, val url: String) { + companion object { + // Branded setup.xml values of enforce_servers must be standard JSON with both name and url set. + // Lenient parsing keeps loose input working, but single quotes, # comments and missing or null fields + // are not parsed and crash the login screen. + @OptIn(ExperimentalSerializationApi::class) + private val json = Json { + ignoreUnknownKeys = true + isLenient = true + allowComments = true + } + + @JvmStatic + fun fromJson(value: String): List = json.decodeFromString(value) + } +} diff --git a/app/src/main/res/values/setup.xml b/app/src/main/res/values/setup.xml index 1c47e9f57d4f..13546310aceb 100644 --- a/app/src/main/res/values/setup.xml +++ b/app/src/main/res/values/setup.xml @@ -131,6 +131,7 @@ +